From 7bb2961bff08b5cd76025eff34e47712f946ee85 Mon Sep 17 00:00:00 2001 From: "Deployment Bot (from Travis CI)" Date: Sun, 17 Jun 2018 17:47:00 +0000 Subject: [PATCH] Deploy ReactPHP Website to github.com/reactphp/reactphp.github.io.git:master --- CNAME | 1 + android-chrome-192x192.png | Bin 0 -> 4556 bytes android-chrome-512x512.png | Bin 0 -> 12680 bytes apple-touch-icon.png | Bin 0 -> 4087 bytes assets/.htaccess | 33 + assets/0.6a34aef149239e7a6f57.js | 1 + assets/19ca4d35c8f94db0fa14422334dd2ad3.woff | Bin 0 -> 18364 bytes assets/72dc47391c5751aa9e94d8d46846e31c.svg | 1 + assets/a7d4d592f015c765bef62de7c96023be.ttf | Bin 0 -> 3516 bytes assets/b2f931638bc837a31b6e7f19c542a289.woff | Bin 0 -> 3592 bytes assets/be4ba3dd17008135675e945b630be8f6.woff | Bin 0 -> 18056 bytes assets/f963ff7998d9564c268d2d32f08aeffc.svg | 24 + assets/main-critical.b3ce38ea4d05827d3ea9.css | 1 + assets/main-critical.b3ce38ea4d05827d3ea9.js | 1 + assets/main.c26014c6022c74ac7c57.css | 1 + assets/main.c26014c6022c74ac7c57.js | 1 + assets/manifest.json | 13 + browserconfig.xml | 9 + cache/changelog.html | 531 ++ cache/index.html | 507 ++ cache/license.html | 387 ++ changelog.html | 6132 +++++++++++++++++ child-process/changelog.html | 622 ++ child-process/index.html | 670 ++ child-process/license.html | 417 ++ datagram/changelog.html | 591 ++ datagram/index.html | 423 ++ datagram/license.html | 393 ++ dns/changelog.html | 1034 +++ dns/index.html | 643 ++ dns/license.html | 492 ++ event-loop/changelog.html | 1128 +++ event-loop/index.html | 1080 +++ event-loop/license.html | 537 ++ favicon-32x32.png | Bin 0 -> 719 bytes favicon.ico | Bin 0 -> 15086 bytes http-client/changelog.html | 1390 ++++ http-client/index.html | 741 ++ http-client/license.html | 582 ++ http/changelog.html | 1467 ++++ http/index.html | 1575 +++++ http/license.html | 552 ++ index.html | 648 ++ manifest.json | 18 + mstile-150x150.png | Bin 0 -> 3973 bytes og-image.png | Bin 0 -> 31391 bytes promise-stream/changelog.html | 508 ++ promise-stream/index.html | 553 ++ promise-stream/license.html | 378 + promise-timer/changelog.html | 575 ++ promise-timer/index.html | 661 ++ promise-timer/license.html | 383 + promise/changelog.html | 946 +++ promise/index.html | 1174 ++++ promise/license.html | 475 ++ robots.txt | 2 + safari-pinned-tab.svg | 1 + socket/changelog.html | 1617 +++++ socket/index.html | 1683 +++++ socket/license.html | 612 ++ stream/changelog.html | 1441 ++++ stream/index.html | 1453 ++++ stream/license.html | 552 ++ 63 files changed, 35660 insertions(+) create mode 100644 CNAME create mode 100644 android-chrome-192x192.png create mode 100644 android-chrome-512x512.png create mode 100644 apple-touch-icon.png create mode 100644 assets/.htaccess create mode 100644 assets/0.6a34aef149239e7a6f57.js create mode 100644 assets/19ca4d35c8f94db0fa14422334dd2ad3.woff create mode 100644 assets/72dc47391c5751aa9e94d8d46846e31c.svg create mode 100644 assets/a7d4d592f015c765bef62de7c96023be.ttf create mode 100644 assets/b2f931638bc837a31b6e7f19c542a289.woff create mode 100644 assets/be4ba3dd17008135675e945b630be8f6.woff create mode 100644 assets/f963ff7998d9564c268d2d32f08aeffc.svg create mode 100644 assets/main-critical.b3ce38ea4d05827d3ea9.css create mode 100644 assets/main-critical.b3ce38ea4d05827d3ea9.js create mode 100644 assets/main.c26014c6022c74ac7c57.css create mode 100644 assets/main.c26014c6022c74ac7c57.js create mode 100644 assets/manifest.json create mode 100644 browserconfig.xml create mode 100644 cache/changelog.html create mode 100644 cache/index.html create mode 100644 cache/license.html create mode 100644 changelog.html create mode 100644 child-process/changelog.html create mode 100644 child-process/index.html create mode 100644 child-process/license.html create mode 100644 datagram/changelog.html create mode 100644 datagram/index.html create mode 100644 datagram/license.html create mode 100644 dns/changelog.html create mode 100644 dns/index.html create mode 100644 dns/license.html create mode 100644 event-loop/changelog.html create mode 100644 event-loop/index.html create mode 100644 event-loop/license.html create mode 100644 favicon-32x32.png create mode 100644 favicon.ico create mode 100644 http-client/changelog.html create mode 100644 http-client/index.html create mode 100644 http-client/license.html create mode 100644 http/changelog.html create mode 100644 http/index.html create mode 100644 http/license.html create mode 100644 index.html create mode 100644 manifest.json create mode 100644 mstile-150x150.png create mode 100644 og-image.png create mode 100644 promise-stream/changelog.html create mode 100644 promise-stream/index.html create mode 100644 promise-stream/license.html create mode 100644 promise-timer/changelog.html create mode 100644 promise-timer/index.html create mode 100644 promise-timer/license.html create mode 100644 promise/changelog.html create mode 100644 promise/index.html create mode 100644 promise/license.html create mode 100644 robots.txt create mode 100644 safari-pinned-tab.svg create mode 100644 socket/changelog.html create mode 100644 socket/index.html create mode 100644 socket/license.html create mode 100644 stream/changelog.html create mode 100644 stream/index.html create mode 100644 stream/license.html diff --git a/CNAME b/CNAME new file mode 100644 index 000000000..77687c8d4 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +reactphp.org diff --git a/android-chrome-192x192.png b/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..7617f1663b3474a3da711edd40f18684f756ec67 GIT binary patch literal 4556 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 literal 0 HcmV?d00001 diff --git a/android-chrome-512x512.png b/android-chrome-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..77bd8c549b334f9cfbefd2638c1ce470c7d0c694 GIT binary patch literal 12680 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 literal 0 HcmV?d00001 diff --git a/apple-touch-icon.png b/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f8c13013ae1f5065b82c5610b280efa07b728b09 GIT binary patch literal 4087 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 AmH+?% literal 0 HcmV?d00001 diff --git a/assets/.htaccess b/assets/.htaccess new file mode 100644 index 000000000..efa53b69c --- /dev/null +++ b/assets/.htaccess @@ -0,0 +1,33 @@ + + ExpiresActive on + ExpiresDefault "access plus 1 month" + + # CSS + ExpiresByType text/css "access plus 1 year" + + # JavaScript + ExpiresByType application/javascript "access plus 1 year" + ExpiresByType application/x-javascript "access plus 1 year" + ExpiresByType text/javascript "access plus 1 year" + + # Web fonts + + # Embedded OpenType (EOT) + ExpiresByType application/vnd.ms-fontobject "access plus 1 month" + ExpiresByType font/eot "access plus 1 month" + + # OpenType + ExpiresByType font/opentype "access plus 1 month" + + # TrueType + ExpiresByType application/x-font-ttf "access plus 1 month" + + # Web Open Font Format (WOFF) 1.0 + ExpiresByType application/font-woff "access plus 1 month" + ExpiresByType application/x-font-woff "access plus 1 month" + ExpiresByType font/woff "access plus 1 month" + + # Web Open Font Format (WOFF) 2.0 + ExpiresByType application/font-woff2 "access plus 1 month" + + diff --git a/assets/0.6a34aef149239e7a6f57.js b/assets/0.6a34aef149239e7a6f57.js new file mode 100644 index 000000000..a2f5e687c --- /dev/null +++ b/assets/0.6a34aef149239e7a6f57.js @@ -0,0 +1 @@ +webpackJsonp([0],Array(33).concat([function(t,e,n){var i=n(54);"string"==typeof i&&(i=[[t.i,i,""]]);var o={};o.transform=void 0;n(32)(i,o);i.locals&&(t.exports=i.locals)},function(t,e,n){"use strict";var i=n(55),o=function(t){return t&&t.__esModule?t:{default:t}}(i);t.exports=o.default},function(t,e,n){"use strict";function i(t){return t.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}var o=n(36);t.exports={isArray:null,isFunction:null,isObject:null,bind:null,each:null,map:null,mixin:null,isMsie:function(){return!!/(msie|trident)/i.test(navigator.userAgent)&&navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2]},escapeRegExChars:function(t){return t.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")},isNumber:function(t){return"number"==typeof t},toStr:function(t){return void 0===t||null===t?"":t+""},cloneDeep:function(t){var e=this.mixin({},t),n=this;return this.each(e,function(t,i){t&&(n.isArray(t)?e[i]=[].concat(t):n.isObject(t)&&(e[i]=n.cloneDeep(t)))}),e},error:function(t){throw new Error(t)},every:function(t,e){var n=!0;return t?(this.each(t,function(i,o){if(!(n=e.call(null,i,o,t)))return!1}),!!n):n},any:function(t,e){var n=!1;return t?(this.each(t,function(i,o){if(e.call(null,i,o,t))return n=!0,!1}),n):n},getUniqueId:function(){var t=0;return function(){return t++}}(),templatify:function(t){if(this.isFunction(t))return t;var e=o.element(t);return"SCRIPT"===e.prop("tagName")?function(){return e.text()}:function(){return String(t)}},defer:function(t){setTimeout(t,0)},noop:function(){},formatPrefix:function(t,e){return e?"":t+"-"},className:function(t,e,n){return(n?"":".")+t+e},escapeHighlightedString:function(t,e,n){e=e||"";var o=document.createElement("div");o.appendChild(document.createTextNode(e)),n=n||"";var r=document.createElement("div");r.appendChild(document.createTextNode(n));var s=document.createElement("div");return s.appendChild(document.createTextNode(t)),s.innerHTML.replace(RegExp(i(o.innerHTML),"g"),e).replace(RegExp(i(r.innerHTML),"g"),n)}}},function(t,e,n){"use strict";t.exports={element:null}},function(t,e){var n=Object.prototype.hasOwnProperty,i=Object.prototype.toString;t.exports=function(t,e,o){if("[object Function]"!==i.call(e))throw new TypeError("iterator must be a function");var r=t.length;if(r===+r)for(var s=0;s=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))}function r(t){var n=this.useColors;if(t[0]=(n?"%c":"")+this.namespace+(n?" %c":" ")+t[0]+(n?"%c ":" ")+"+"+e.humanize(this.diff),n){var i="color: "+this.color;t.splice(1,0,i,"color: inherit");var o=0,r=0;t[0].replace(/%[a-zA-Z%]/g,function(t){"%%"!==t&&(o++,"%c"===t&&(r=o))}),t.splice(r,0,i)}}function s(){return"object"==typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}function a(t){try{null==t?e.storage.removeItem("debug"):e.storage.debug=t}catch(t){}}function u(){var t;try{t=e.storage.debug}catch(t){}return!t&&void 0!==i&&"env"in i&&(t=i.env.DEBUG),t}e=t.exports=n(72),e.log=s,e.formatArgs=r,e.save=a,e.load=u,e.useColors=o,e.storage="undefined"!=typeof chrome&&void 0!==chrome.storage?chrome.storage.local:function(){try{return window.localStorage}catch(t){}}(),e.colors=["lightseagreen","forestgreen","goldenrod","dodgerblue","darkorchid","crimson"],e.formatters.j=function(t){try{return JSON.stringify(t)}catch(t){return"[UnexpectedJSONParseError]: "+t.message}},e.enable(u())}).call(e,n(3))},function(t,e,n){"use strict";function i(t,e){var i=n(37),o=this;"function"==typeof Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):o.stack=(new Error).stack||"Cannot get a stacktrace, browser is too old",this.name="AlgoliaSearchError",this.message=t||"Unknown error",e&&i(e,function(t,e){o[e]=t})}function o(t,e){function n(){var n=Array.prototype.slice.call(arguments,0);"string"!=typeof n[0]&&n.unshift(e),i.apply(this,n),this.name="AlgoliaSearch"+t+"Error"}return r(n,i),n}var r=n(45);r(i,Error),t.exports={AlgoliaSearchError:i,UnparsableJSON:o("UnparsableJSON","Could not parse the incoming response as JSON, see err.more for details"),RequestTimeout:o("RequestTimeout","Request timedout before getting a response"),Network:o("Network","Network issue, see err.more for details"),JSONPScriptFail:o("JSONPScriptFail"," + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

Cache Changelog

+ + + +

+ + 2017 +

+ + +

+ + + 0.4.2 + + + (2017-12-20) + + Release on GitHub + + +

+ +
    +
  • +

    Improve documentation with usage and installation instructions
    +(#10 by @clue)

    +
  • +
  • +

    Improve test suite by adding PHPUnit to require-dev and
    +add forward compatibility with PHPUnit 5 and PHPUnit 6 and
    +sanitize Composer autoload paths
    +(#14 by @shaunbramley and #12 and #18 by @clue)

    +
  • +
+ +
+

+ + 2016 +

+ + +

+ + + 0.4.1 + + + (2016-02-25) + + Release on GitHub + + +

+ +
    +
  • Repository maintenance, split off from main repo, improve test suite and documentation
  • +
  • First class support for PHP7 and HHVM (#9 by @clue)
  • +
  • Adjust compatibility to 5.3 (#7 by @clue)
  • +
+ +
+

+ + 2014 +

+ + +

+ + + 0.4.0 + + + (2014-02-02) + + Release on GitHub + + +

+ +
    +
  • BC break: Bump minimum PHP version to PHP 5.4, remove 5.3 specific hacks
  • +
  • BC break: Update to React/Promise 2.0
  • +
  • Dependency: Autoloading and filesystem structure now PSR-4 instead of PSR-0
  • +
+ +
+

+ + 2013 +

+ + +

+ + + 0.3.2 + + + (2013-04-24) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + 0.3.0 + + + (2013-01-20) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+

+ + 2012 +

+ + +

+ + + 0.2.6 + + + (2012-12-24) + + Release on GitHub + + +

+ +
    +
  • Feature: New cache component, used by DNS
  • +
+ +
+
+ +
+
+
+ + + + + + diff --git a/cache/index.html b/cache/index.html new file mode 100644 index 000000000..84ab53805 --- /dev/null +++ b/cache/index.html @@ -0,0 +1,507 @@ + + + + + + + + Cache: +Cache Component - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

Cache

+ + +

Build Status Code Climate

+

Async, Promise-based cache interface +for ReactPHP.

+

The cache component provides a +Promise-based +CacheInterface and an in-memory ArrayCache +implementation of that. +This allows consumers to type hint against the interface and third parties to +provide alternate implementations.

+

Table of Contents

+ +

+Usage

+

+CacheInterface

+

The CacheInterface describes the main interface of this component. +This allows consumers to type hint against the interface and third parties to +provide alternate implementations.

+

+get()

+
$cache
+    ->get('foo')
+    ->then('var_dump');
+

This example fetches the value of the key foo and passes it to the +var_dump function. You can use any of the composition provided by +promises.

+

If the key foo does not exist, the promise will be rejected.

+

+set()

+
$cache->set('foo', 'bar');
+

This example eventually sets the value of the key foo to bar. If it +already exists, it is overridden. No guarantees are made as to when the cache +value is set. If the cache implementation has to go over the network to store +it, it may take a while.

+

+remove()

+
$cache->remove('foo');
+

This example eventually removes the key foo from the cache. As with set, +this may not happen instantly.

+

+ArrayCache

+

The ArrayCache provides an in-memory implementation of the +CacheInterface.

+
$cache = new ArrayCache();
+
+$cache->set('foo', 'bar');
+

+Common usage

+

+Fallback get

+

A common use case of caches is to attempt fetching a cached value and as a +fallback retrieve it from the original data source if not found. Here is an +example of that:

+
$cache
+    ->get('foo')
+    ->then(null, 'getFooFromDb')
+    ->then('var_dump');
+

First an attempt is made to retrieve the value of foo. A promise rejection +handler of the function getFooFromDb is registered. getFooFromDb is a +function (can be any PHP callable) that will be called if the key does not +exist in the cache.

+

getFooFromDb can handle the missing key by returning a promise for the +actual value from the database (or any other data source). As a result, this +chain will correctly fall back, and provide the value in both cases.

+

+Fallback get and set

+

To expand on the fallback get example, often you want to set the value on the +cache after fetching it from the data source.

+
$cache
+    ->get('foo')
+    ->then(null, array($this, 'getAndCacheFooFromDb'))
+    ->then('var_dump');
+
+public function getAndCacheFooFromDb()
+{
+    return $this->db
+        ->get('foo')
+        ->then(array($this, 'cacheFooFromDb'));
+}
+
+public function cacheFooFromDb($foo)
+{
+    $this->cache->set('foo', $foo);
+
+    return $foo;
+}
+

By using chaining you can easily conditionally cache the value if it is +fetched from the database.

+

+Install

+

The recommended way to install this library is through Composer. +New to Composer?

+

This will install the latest supported version:

+
$ composer require react/cache:^0.4.2
+

See also the CHANGELOG for details about version upgrades.

+

This project aims to run on any platform and thus does not require any PHP +extensions and supports running on legacy PHP 5.3 through current PHP 7+ and +HHVM. +It's highly recommended to use PHP 7+ for this project.

+

+Tests

+

To run the test suite, you first need to clone this repo and then install all +dependencies through Composer:

+
$ composer install
+

To run the test suite, go to the project root and run:

+
$ php vendor/bin/phpunit
+

+License

+

MIT, see LICENSE file.

+
+ +
+
+
+ + + + + + diff --git a/cache/license.html b/cache/license.html new file mode 100644 index 000000000..31db051f2 --- /dev/null +++ b/cache/license.html @@ -0,0 +1,387 @@ + + + + + + + + Cache: License - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

Cache License

+ +

Copyright (c) 2012 Igor Wiedler, Chris Boden

+

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions:

+

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.

+
+ +
+
+
+ + + + + + diff --git a/changelog.html b/changelog.html new file mode 100644 index 000000000..b6afd2e4a --- /dev/null +++ b/changelog.html @@ -0,0 +1,6132 @@ + + + + + + + + Changelog - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+
+

+Changelog

+

The combined changelog for all ReactPHP components.

+ + + + +

+ + 2018 +

+ + +

+ + + PromiseTimer 1.5.0 + + + (2018-06-13) + + Release on GitHub + + +

+ +
    +
  • Feature: Improve memory consumption by cleaning up garbage references to pending promise without canceller.
    +(#34 by @clue)
  • +
+ +
+ +

+ + + Promise 2.7.0 + + + (2018-06-13) + + Release on GitHub + + +

+ +
    +
  • Feature: Improve memory consumption for pending promises by using static internal callbacks without binding to self.
    +(#124 by @clue)
  • +
+ +
+ +

+ + + Socket 0.8.12 + + + (2018-06-11) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Improve memory consumption for failed and cancelled connection attempts.
    +(#161 by @clue)

    +
  • +
  • +

    Improve test suite to fix Travis config to test against legacy PHP 5.3 again.
    +(#162 by @clue)

    +
  • +
+ +
+ +

+ + + PromiseTimer 1.4.0 + + + (2018-06-11) + + Release on GitHub + + +

+ +
    +
  • Feature: Improve memory consumption by cleaning up garbage references.
    +(#33 by @clue)
  • +
+ +
+ +

+ + + Promise 2.6.0 + + + (2018-06-11) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Significantly improve memory consumption and performance by only passing resolver args
    +to resolver and canceller if callback requires them. Also use static callbacks without
    +binding to promise, clean up canceller function reference when they are no longer
    +needed and hide resolver and canceller references from call stack on PHP 7+.
    +(#113, #115, #116, #117, #118, #119 and #123 by @clue)

    +

    These changes combined mean that rejecting promises with an Exception should
    +no longer cause any internal circular references which could cause some unexpected
    +memory growth in previous versions. By explicitly avoiding and explicitly
    +cleaning up said references, we can avoid relying on PHP's circular garbage collector
    +to kick in which significantly improves performance when rejecting many promises.

    +
  • +
  • +

    Mark legacy progress support / notification API as deprecated
    +(#112 by @clue)

    +
  • +
  • +

    Recommend rejecting promises by throwing an exception
    +(#114 by @jsor)

    +
  • +
  • +

    Improve documentation to properly instantiate LazyPromise
    +(#121 by @holtkamp)

    +
  • +
  • +

    Follower cancellation propagation was originally planned for this release
    +but has been reverted for now and is planned for a future release.
    +(#99 by @jsor and #122 by @clue)

    +
  • +
+ +
+ +

+ + + PromiseTimer 1.3.0 + + + (2018-04-24) + + Release on GitHub + + +

+ +
    +
  • Feature: Improve memory consumption by cleaning up unneeded references.
    +(#32 by @clue)
  • +
+ +
+ +

+ + + Socket 0.8.11 + + + (2018-04-24) + + Release on GitHub + + +

+ +
    +
  • Feature: Improve memory consumption for cancelled connection attempts and
    +simplify skipping DNS lookup when connecting to IP addresses.
    +(#159 and #160 by @clue)
  • +
+ +
+ +

+ + + EventLoop 0.5.2 + + + (2018-04-24) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Improve memory consumption and runtime performance for StreamSelectLoop timers.
    +(#164 by @clue)

    +
  • +
  • +

    Improve test suite by removing I/O dependency at StreamSelectLoopTest to fix Mac OS X tests.
    +(#161 by @nawarian)

    +
  • +
+ +
+ +

+ + + HTTP 0.8.3 + + + (2018-04-11) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Do not pause connection stream to detect closed connections immediately.
    +(#315 by @clue)

    +
  • +
  • +

    Feature: Keep incoming Transfer-Encoding: chunked request header.
    +(#316 by @clue)

    +
  • +
  • +

    Feature: Reject invalid requests that contain both Content-Length and Transfer-Encoding request headers.
    +(#318 by @clue)

    +
  • +
  • +

    Minor internal refactoring to simplify connection close logic after sending response.
    +(#317 by @clue)

    +
  • +
+ +
+ +

+ + + HTTPClient 0.5.9 + + + (2018-04-10) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Support legacy HTTP servers that use only LF instead of CRLF.
    +(#130 by @clue)

    +
  • +
  • +

    Improve test suite by applying maximum test timeouts for integration tests.
    +(#131 by @clue)

    +
  • +
+ +
+ +

+ + + EventLoop 0.5.1 + + + (2018-04-09) + + Release on GitHub + + +

+ + + +
+ +

+ + + HTTP 0.8.2 + + + (2018-04-06) + + Release on GitHub + + +

+ +
    +
  • +

    Fix: Do not pass $next handler to final request handler.
    +(#308 by @clue)

    +
  • +
  • +

    Fix: Fix awaiting queued handlers when cancelling a queued handler.
    +(#313 by @clue)

    +
  • +
  • +

    Fix: Fix Server to skip SERVER_ADDR params for Unix domain sockets (UDS).
    +(#307 by @clue)

    +
  • +
  • +

    Documentation for PSR-15 middleware and minor documentation improvements.
    +(#314 by @clue and #297, #298 and #310 by @seregazhuk)

    +
  • +
  • +

    Minor code improvements and micro optimizations.
    +(#301 by @seregazhuk and #305 by @kalessil)

    +
  • +
+ +
+ +

+ + + EventLoop 0.5.0 + + + (2018-04-05) + + Release on GitHub + + +

+ +

A major feature release with a significant documentation overhaul and long overdue API cleanup!

+

This update involves a number of BC breaks due to dropped support for deprecated
+functionality. We've tried hard to avoid BC breaks where possible and minimize
+impact otherwise. We expect that most consumers of this package will actually
+not be affected by any BC breaks, see below for more details.

+

We realize that the changes listed below may seem overwhelming, but we've tried
+to be very clear about any possible BC breaks. Don't worry: In fact, all ReactPHP
+components are already compatible and support both this new release as well as
+providing backwards compatibility with the last release.

+
    +
  • +

    Feature / BC break: Add support for signal handling via new
    +LoopInterface::addSignal() and LoopInterface::removeSignal() methods.
    +(#104 by @WyriHaximus and #111 and #150 by @clue)

    +
    $loop->addSignal(SIGINT, function () {
    +    echo 'CTRL-C';
    +});
    +
  • +
  • +

    Feature: Significant documentation updates for LoopInterface and Factory.
    +(#100, #119, #126, #127, #159 and #160 by @clue, #113 by @WyriHaximus and #81 and #91 by @jsor)

    +
  • +
  • +

    Feature: Add examples to ease getting started
    +(#99, #100 and #125 by @clue, #59 by @WyriHaximus and #143 by @jsor)

    +
  • +
  • +

    Feature: Documentation for advanced timer concepts, such as monotonic time source vs wall-clock time
    +and high precision timers with millisecond accuracy or below.
    +(#130 and #157 by @clue)

    +
  • +
  • +

    Feature: Documentation for advanced stream concepts, such as edge-triggered event listeners
    +and stream buffers and allow throwing Exception if stream resource is not supported.
    +(#129 and #158 by @clue)

    +
  • +
  • +

    Feature: Throw BadMethodCallException on manual loop creation when required extension isn't installed.
    +(#153 by @WyriHaximus)

    +
  • +
  • +

    Feature / BC break: First class support for legacy PHP 5.3 through PHP 7.2 and HHVM
    +and remove all callable type hints for consistency reasons.
    +(#141 and #151 by @clue)

    +
  • +
  • +

    BC break: Documentation for timer API and clean up unneeded timer API.
    +(#102 by @clue)

    +

    Remove TimerInterface::cancel(), use LoopInterface::cancelTimer() instead:

    +
    // old (method invoked on timer instance)
    +$timer->cancel();
    +
    +// already supported before: invoke method on loop instance
    +$loop->cancelTimer($timer);
    +

    Remove unneeded TimerInterface::setData() and TimerInterface::getData(),
    +use closure binding to add arbitrary data to timer instead:

    +
    // old (limited setData() and getData() only allows single variable)
    +$name = 'Tester';
    +$timer = $loop->addTimer(1.0, function ($timer) {
    +    echo 'Hello ' . $timer->getData() . PHP_EOL;
    +});
    +$timer->setData($name);
    +
    +// already supported before: closure binding allows any number of variables
    +$name = 'Tester';
    +$loop->addTimer(1.0, function () use ($name) {
    +    echo 'Hello ' . $name . PHP_EOL;
    +});
    +

    Remove unneeded TimerInterface::getLoop(), use closure binding instead:

    +
    // old (getLoop() called on timer instance)
    +$loop->addTimer(0.1, function ($timer) {
    +    $timer->getLoop()->stop();
    +});
    +
    +// already supported before: use closure binding as usual
    +$loop->addTimer(0.1, function () use ($loop) {
    +    $loop->stop();
    +});
    +
  • +
  • +

    BC break: Remove unneeded LoopInterface::isTimerActive() and
    +TimerInterface::isActive() to reduce API surface.
    +(#133 by @clue)

    +
    // old (method on timer instance or on loop instance)
    +$timer->isActive();
    +$loop->isTimerActive($timer);
    +
  • +
  • +

    BC break: Move TimerInterface one level up to React\EventLoop\TimerInterface.
    +(#138 by @WyriHaximus)

    +
    // old (notice obsolete "Timer" namespace)
    +assert($timer instanceof React\EventLoop\Timer\TimerInterface);
    +
    +// new
    +assert($timer instanceof React\EventLoop\TimerInterface);
    +
  • +
  • +

    BC break: Remove unneeded LoopInterface::nextTick() (and internal NextTickQueue),
    +use LoopInterface::futureTick() instead.
    +(#30 by @clue)

    +
    // old (removed)
    +$loop->nextTick(function () {
    +    echo 'tick';
    +});
    +
    +// already supported before
    +$loop->futureTick(function () {
    +    echo 'tick';
    +});
    +
  • +
  • +

    BC break: Remove unneeded $loop argument for LoopInterface::futureTick()
    +(and fix internal cyclic dependency).
    +(#103 by @clue)

    +
    // old ($loop gets passed by default)
    +$loop->futureTick(function ($loop) {
    +    $loop->stop();
    +});
    +
    +// already supported before: use closure binding as usual
    +$loop->futureTick(function () use ($loop) {
    +    $loop->stop();
    +});
    +
  • +
  • +

    BC break: Remove unneeded LoopInterface::tick().
    +(#72 by @jsor)

    +
    // old (removed)
    +$loop->tick();
    +
    +// suggested work around for testing purposes only
    +$loop->futureTick(function () use ($loop) {
    +    $loop->stop();
    +});
    +
  • +
  • +

    BC break: Documentation for advanced stream API and clean up unneeded stream API.
    +(#110 by @clue)

    +

    Remove unneeded $loop argument for LoopInterface::addReadStream()
    +and LoopInterface::addWriteStream(), use closure binding instead:

    +
    // old ($loop gets passed by default)
    +$loop->addReadStream($stream, function ($stream, $loop) {
    +    $loop->removeReadStream($stream);
    +});
    +
    +// already supported before: use closure binding as usual
    +$loop->addReadStream($stream, function ($stream) use ($loop) {
    +    $loop->removeReadStream($stream);
    +});
    +
  • +
  • +

    BC break: Remove unneeded LoopInterface::removeStream() method,
    +use LoopInterface::removeReadStream() and LoopInterface::removeWriteStream() instead.
    +(#118 by @clue)

    +
    // old
    +$loop->removeStream($stream);
    +
    +// already supported before
    +$loop->removeReadStream($stream);
    +$loop->removeWriteStream($stream);
    +
  • +
  • +

    BC break: Rename LibEventLoop to ExtLibeventLoop and LibEvLoop to ExtLibevLoop
    +for consistent naming for event loop implementations.
    +(#128 by @clue)

    +
  • +
  • +

    BC break: Remove optional EventBaseConfig argument from ExtEventLoop
    +and make its FEATURE_FDS enabled by default.
    +(#156 by @WyriHaximus)

    +
  • +
  • +

    BC break: Mark all classes as final to discourage inheritance.
    +(#131 by @clue)

    +
  • +
  • +

    Fix: Fix ExtEventLoop to keep track of stream resources (refcount)
    +(#123 by @clue)

    +
  • +
  • +

    Fix: Ensure large timer interval does not overflow on 32bit systems
    +(#132 by @clue)

    +
  • +
  • +

    Fix: Fix separately removing readable and writable side of stream when closing
    +(#139 by @clue)

    +
  • +
  • +

    Fix: Properly clean up event watchers for ext-event and ext-libev
    +(#149 by @clue)

    +
  • +
  • +

    Fix: Minor code cleanup and remove unneeded references
    +(#145 by @seregazhuk)

    +
  • +
  • +

    Fix: Discourage outdated ext-libevent on PHP 7
    +(#62 by @cboden)

    +
  • +
  • +

    Improve test suite by adding forward compatibility with PHPUnit 6 and PHPUnit 5,
    +lock Travis distro so new defaults will not break the build,
    +improve test suite to be less fragile and increase test timeouts,
    +test against PHP 7.2 and reduce fwrite() call length to one chunk.
    +(#106 and #144 by @clue, #120 and #124 by @carusogabriel, #147 by nawarian and #92 by @kelunik)

    +
  • +
  • +

    A number of changes were originally planned for this release but have been backported
    +to the last v0.4.3 already: #74, #76, #79, #81 (refs #65, #66, #67), #88 and #93

    +
  • +
+ +
+ +

+ + + Datagram 1.4.0 + + + (2018-02-28) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Update DNS dependency to support loading system default DNS
    +nameserver config on all supported platforms
    +(/etc/resolv.conf on Unix/Linux/Mac/Docker/WSL and WMIC on Windows)
    +(#23 by @clue)

    +

    This means that connecting to hosts that are managed by a local DNS server,
    +such as a corporate DNS server or when using Docker containers, will now
    +work as expected across all platforms with no changes required:

    +
    $factory = new Factory($loop);
    +$factory->createClient('intranet.example:5353');
    +
  • +
  • +

    Improve README
    +(#22 by @jsor)

    +
  • +
+ +
+ +

+ + + Socket 0.8.10 + + + (2018-02-28) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Update DNS dependency to support loading system default DNS
    +nameserver config on all supported platforms
    +(/etc/resolv.conf on Unix/Linux/Mac/Docker/WSL and WMIC on Windows)
    +(#152 by @clue)

    +

    This means that connecting to hosts that are managed by a local DNS server,
    +such as a corporate DNS server or when using Docker containers, will now
    +work as expected across all platforms with no changes required:

    +
    $connector = new Connector($loop);
    +$connector->connect('intranet.example:80')->then(function ($connection) {
    +    //
    +});
    +
  • +
+ +
+ +

+ + + DNS 0.4.13 + + + (2018-02-27) + + Release on GitHub + + +

+ +
    +
  • +

    Add Config::loadSystemConfigBlocking() to load default system config
    +and support parsing DNS config on all supported platforms
    +(/etc/resolv.conf on Unix/Linux/Mac and WMIC on Windows)
    +(#92, #93, #94 and #95 by @clue)

    +
    $config = Config::loadSystemConfigBlocking();
    +$server = $config->nameservers ? reset($config->nameservers) : '8.8.8.8';
    +
  • +
  • +

    Remove unneeded cyclic dependency on react/socket
    +(#96 by @clue)

    +
  • +
+ +
+ +

+ + + HTTPClient 0.5.8 + + + (2018-02-09) + + Release on GitHub + + +

+ +
    +
  • +

    Support legacy PHP 5.3 through PHP 7.2 and HHVM
    +(#126 and #127 by @clue)

    +
  • +
  • +

    Improve backwards compatibility with Promise v1 and
    +use RingCentral to improve interoperability with react/http.
    +(#124 and #125 by @clue)

    +
  • +
+ +
+ +

+ + + HTTPClient 0.5.7 + + + (2018-02-08) + + Release on GitHub + + +

+ +
    +
  • +

    Fix: Ignore excessive whitespace in chunk header for Transfer-Encoding: chunked
    +(#123 by @DangerLifter and @clue)

    +
  • +
  • +

    Fix: Ignore invalid incoming Transfer-Encoding response header
    +(#122 by @clue)

    +
  • +
  • +

    Improve documentation for Client (and advanced Connector)
    +(#111 by @jsor and #121 by @clue)

    +
  • +
  • +

    Improve test suite by adding support for PHPUnit 6
    +(#112 by @carusogabriel)

    +
  • +
+ +
+ +

+ + + Stream 0.7.7 + + + (2018-01-19) + + Release on GitHub + + +

+ +
    +
  • Improve test suite by fixing forward compatibility with upcoming EventLoop
    +releases, avoid risky tests and add test group to skip integration tests
    +relying on internet connection and apply appropriate test timeouts.
    +(#128, #131 and #132 by @clue)
  • +
+ +
+ +

+ + + ChildProcess 0.5.2 + + + (2018-01-18) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Detect "exit" immediately if last process pipe is closed
    +(#58 by @clue)

    +

    This introduces a simple check to see if the program is already known to be
    +closed when the last process pipe is closed instead of relying on a periodic
    +timer. This simple change improves "exit" detection significantly for most
    +programs and does not cause a noticeable penalty for more advanced use cases.

    +
  • +
  • +

    Fix forward compatibility with upcoming EventLoop releases
    +(#56 by @clue)

    +
  • +
+ +
+ +

+ + + Socket 0.8.9 + + + (2018-01-18) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Support explicitly choosing TLS version to negotiate with remote side
    +by respecting crypto_method context parameter for all classes.
    +(#149 by @clue)

    +

    By default, all connector and server classes support TLSv1.0+ and exclude
    +support for legacy SSLv2/SSLv3. As of PHP 5.6+ you can also explicitly
    +choose the TLS version you want to negotiate with the remote side:

    +
    // new: now supports 'crypto_method` context parameter for all classes
    +$connector = new Connector($loop, array(
    +    'tls' => array(
    +        'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
    +    )
    +));
    +
  • +
  • +

    Minor internal clean up to unify class imports
    +(#148 by @clue)

    +
  • +
+ +
+ +

+ + + DNS 0.4.12 + + + (2018-01-14) + + Release on GitHub + + +

+ +
    +
  • Improve test suite by adding forward compatibility with PHPUnit 6,
    +test against PHP 7.2, fix forward compatibility with upcoming EventLoop releases,
    +add test group to skip integration tests relying on internet connection
    +and add minor documentation improvements.
    +(#85 and #87 by @carusogabriel, #88 and #89 by @clue and #83 by @jsor)
  • +
+ +
+ +

+ + + Socket 0.8.8 + + + (2018-01-06) + + Release on GitHub + + +

+ +
    +
  • Improve test suite by adding test group to skip integration tests relying on
    +internet connection and fix minor documentation typo.
    +(#146 by @clue and #145 by @cn007b)
  • +
+ +
+ +

+ + + HTTP 0.8.1 + + + (2018-01-05) + + Release on GitHub + + +

+ +
    +
  • +

    Major request handler performance improvement. Benchmarks suggest number of
    +requests/s improved by more than 50% for common GET requests!
    +We now avoid queuing, buffering and wrapping incoming requests in promises
    +when we're below limits and instead can directly process common requests.
    +(#291, #292, #293, #294 and #296 by @clue)

    +
  • +
  • +

    Fix: Fix concurrent invoking next middleware request handlers
    +(#293 by @clue)

    +
  • +
  • +

    Small code improvements
    +(#286 by @seregazhuk)

    +
  • +
  • +

    Improve test suite to be less fragile when using ext-event and
    +fix test suite forward compatibility with upcoming EventLoop releases
    +(#288 and #290 by @clue)

    +
  • +
+ +
+

+ + 2017 +

+ + +

+ + + Socket 0.8.7 + + + (2017-12-24) + + Release on GitHub + + +

+ +
    +
  • +

    Fix: Fix closing socket resource before removing from loop
    +(#141 by @clue)

    +

    This fixes the root cause of an uncaught Exception that only manifested
    +itself after the recent Stream v0.7.4 component update and only if you're
    +using ext-event (ExtEventLoop).

    +
  • +
  • +

    Improve test suite by testing against PHP 7.2
    +(#140 by @carusogabriel)

    +
  • +
+ +
+ +

+ + + PromiseTimer 1.2.1 + + + (2017-12-22) + + Release on GitHub + + +

+ +
    +
  • +

    README improvements
    +(#28 by @jsor)

    +
  • +
  • +

    Improve test suite by adding forward compatiblity with PHPUnit 6 and
    +fix test suite forward compatibility with upcoming EventLoop releases
    +(#30 and #31 by @clue)

    +
  • +
+ +
+ +

+ + + PromiseStream 1.1.1 + + + (2017-12-22) + + Release on GitHub + + +

+ +
    +
  • +

    Fix: Fix all() to assume null values if no event data is passed
    +(#13 by @clue)

    +
  • +
  • +

    Improve test suite by simplifying test bootstrapping logic via Composer and
    +add forward compatibility with PHPUnit 5 and PHPUnit 6 and
    +test against PHP 7.1 and 7.2
    +(#11 and #12 by @clue and #9 by @carusogabriel)

    +
  • +
+ +
+ +

+ + + ChildProcess 0.5.1 + + + (2017-12-22) + + Release on GitHub + + +

+ +
    +
  • +

    Fix: Update Stream dependency to work around SEGFAULT in legacy PHP < 5.4.28
    +and PHP < 5.5.12
    +(#50 and #52 by @clue)

    +
  • +
  • +

    Improve test suite by simplifying test bootstrapping logic via Composer and
    +adding forward compatibility with PHPUnit 6
    +(#53, #54 and #55 by @clue)

    +
  • +
+ +
+ +

+ + + Stream 0.7.6 + + + (2017-12-21) + + Release on GitHub + + +

+ +
    +
  • +

    Fix: Work around reading from unbuffered pipe stream in legacy PHP < 5.4.28 and PHP < 5.5.12
    +(#126 by @clue)

    +
  • +
  • +

    Improve test suite by simplifying test bootstrapping logic via Composer and
    +test against PHP 7.2
    +(#127 by @clue and #124 by @carusogabriel)

    +
  • +
+ +
+ +

+ + + Cache 0.4.2 + + + (2017-12-20) + + Release on GitHub + + +

+ +
    +
  • +

    Improve documentation with usage and installation instructions
    +(#10 by @clue)

    +
  • +
  • +

    Improve test suite by adding PHPUnit to require-dev and
    +add forward compatibility with PHPUnit 5 and PHPUnit 6 and
    +sanitize Composer autoload paths
    +(#14 by @shaunbramley and #12 and #18 by @clue)

    +
  • +
+ +
+ +

+ + + HTTP 0.8.0 + + + (2017-12-12) + + Release on GitHub + + +

+ +
    +
  • +

    Feature / BC break: Add new Server facade that buffers and parses incoming
    +HTTP requests. This provides full PSR-7 compatibility, including support for
    +form submissions with POST fields and file uploads.
    +The old Server has been renamed to StreamingServer for advanced usage
    +and is used internally.
    +(#266, #271, #281, #282, #283 and #284 by @WyriHaximus and @clue)

    +
    // old: handle incomplete/streaming requests
    +$server = new Server($handler);
    +
    +// new: handle complete, buffered and parsed requests
    +// new: full PSR-7 support, including POST fields and file uploads
    +$server = new Server($handler);
    +
    +// new: handle incomplete/streaming requests
    +$server = new StreamingServer($handler);
    +
    +

    While this is technically a small BC break, this should in fact not break
    +most consuming code. If you rely on the old request streaming, you can
    +explicitly use the advanced StreamingServer to restore old behavior.

    +
    +
  • +
  • +

    Feature: Add support for middleware request handler arrays
    +(#215, #228, #229, #236, #237, #238, #246, #247, #277, #279 and #285 by @WyriHaximus, @clue and @jsor)

    +
    // new: middleware request handler arrays
    +$server = new Server(array(
    +    function (ServerRequestInterface $request, callable $next) {
    +        $request = $request->withHeader('Processed', time());
    +        return $next($request);
    +    },
    +    function (ServerRequestInterface $request) {
    +        return new Response();
    +    }
    +));
    +
  • +
  • +

    Feature: Add support for limiting how many next request handlers can be
    +executed concurrently (LimitConcurrentRequestsMiddleware)
    +(#272 by @clue and @WyriHaximus)

    +
    // new: explicitly limit concurrency
    +$server = new Server(array(
    +    new LimitConcurrentRequestsMiddleware(10),
    +    $handler
    +));
    +
  • +
  • +

    Feature: Add support for buffering the incoming request body
    +(RequestBodyBufferMiddleware).
    +This feature mimics PHP's default behavior and respects its post_max_size
    +ini setting by default and allows explicit configuration.
    +(#216, #224, #263, #276 and #278 by @WyriHaximus and #235 by @andig)

    +
    // new: buffer up to 10 requests with 8 MiB each
    +$server = new StreamingServer(array(
    +    new LimitConcurrentRequestsMiddleware(10),
    +    new RequestBodyBufferMiddleware('8M'),
    +    $handler
    +));
    +
  • +
  • +

    Feature: Add support for parsing form submissions with POST fields and file
    +uploads (RequestBodyParserMiddleware).
    +This feature mimics PHP's default behavior and respects its ini settings and
    +MAX_FILE_SIZE POST fields by default and allows explicit configuration.
    +(#220, #226, #252, #261, #264, #265, #267, #268, #274 by @WyriHaximus and @clue)

    +
    // new: buffer up to 10 requests with 8 MiB each
    +// and limit to 4 uploads with 2 MiB each
    +$server = new StreamingServer(array(
    +    new LimitConcurrentRequestsMiddleware(10),
    +    new RequestBodyBufferMiddleware('8M'),
    +    new RequestBodyParserMiddleware('2M', 4)
    +    $handler
    +));
    +
  • +
  • +

    Feature: Update Socket to work around sending secure HTTPS responses with PHP < 7.1.4
    +(#244 by @clue)

    +
  • +
  • +

    Feature: Support sending same response header multiple times (e.g. Set-Cookie)
    +(#248 by @clue)

    +
  • +
  • +

    Feature: Raise maximum request header size to 8k to match common implementations
    +(#253 by @clue)

    +
  • +
  • +

    Improve test suite by adding forward compatibility with PHPUnit 6, test
    +against PHP 7.1 and PHP 7.2 and refactor and remove risky and duplicate tests.
    +(#243, #269 and #270 by @carusogabriel and #249 by @clue)

    +
  • +
  • +

    Minor code refactoring to move internal classes to React\Http\Io namespace
    +and clean up minor code and documentation issues
    +(#251 by @clue, #227 by @kalessil, #240 by @christoph-kluge, #230 by @jsor and #280 by @andig)

    +
  • +
+ +
+ +

+ + + PromiseStream 1.1.0 + + + (2017-11-28) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Reject first() when stream emits an error event
    +(#7 by @clue)

    +
  • +
  • +

    Fix: Explicit close() of unwrapped stream should not emit error event
    +(#8 by @clue)

    +
  • +
  • +

    Internal refactoring to simplify buffer() function
    +(#6 by @kelunik)

    +
  • +
+ +
+ +

+ + + Stream 0.7.5 + + + (2017-11-20) + + Release on GitHub + + +

+ +
    +
  • +

    Fix: Igore excessive fopen() mode flags for WritableResourceStream
    +(#119 by @clue)

    +
  • +
  • +

    Fix: Fix forward compatibility with upcoming EventLoop releases
    +(#121 by @clue)

    +
  • +
  • +

    Restructure examples to ease getting started
    +(#123 by @clue)

    +
  • +
  • +

    Improve test suite by adding forward compatibility with PHPUnit 6 and
    +ignore Mac OS X test failures for now until Travis tests work again
    +(#122 by @gabriel-caruso and #120 by @clue)

    +
  • +
+ +
+ +

+ + + Socket 0.8.6 + + + (2017-11-18) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Add Unix domain socket (UDS) support to Server with unix:// URI scheme
    +and add advanced UnixServer class.
    +(#120 by @andig)

    +
    // new: Server now supports "unix://" scheme
    +$server = new Server('unix:///tmp/server.sock', $loop);
    +
    +// new: advanced usage
    +$server = new UnixServer('/tmp/server.sock', $loop);
    +
  • +
  • +

    Restructure examples to ease getting started
    +(#136 by @clue)

    +
  • +
  • +

    Improve test suite by adding forward compatibility with PHPUnit 6 and
    +ignore Mac OS X test failures for now until Travis tests work again
    +(#133 by @gabriel-caruso and #134 by @clue)

    +
  • +
+ +
+ +

+ + + PromiseStream 1.0.0 + + + (2017-10-24) + + Release on GitHub + + +

+ +
    +
  • First stable release, now following SemVer
  • +
+
+

Contains no other changes, so it's actually fully compatible with the v0.1.2 release.

+
+ +
+ +

+ + + Socket 0.8.5 + + + (2017-10-23) + + Release on GitHub + + +

+ +
    +
  • +

    Fix: Work around PHP bug with Unix domain socket (UDS) paths for Mac OS X
    +(#123 by @andig)

    +
  • +
  • +

    Fix: Fix SecureServer to return null URI if server socket is already closed
    +(#129 by @clue)

    +
  • +
  • +

    Improve test suite by adding forward compatibility with PHPUnit v5 and
    +forward compatibility with upcoming EventLoop releases in tests and
    +test Mac OS X on Travis
    +(#122 by @andig and #125, #127 and #130 by @clue)

    +
  • +
  • +

    Readme improvements
    +(#118 by @jsor)

    +
  • +
+ +
+ +

+ + + PromiseStream 0.1.2 + + + (2017-10-18) + + Release on GitHub + + +

+ +
    +
  • Feature: Optional maximum buffer length for buffer() (#3 by @WyriHaximus)
  • +
  • Improvement: Readme improvements (#5 by @jsor)
  • +
+ +
+ +

+ + + Stream 0.7.4 + + + (2017-10-11) + + Release on GitHub + + +

+ +
    +
  • +

    Fix: Remove event listeners from CompositeStream once closed and
    +remove undocumented left-over close event argument
    +(#116 by @clue)

    +
  • +
  • +

    Minor documentation improvements: Fix wrong class name in example,
    +fix typos in README and
    +fix forward compatibility with upcoming EventLoop releases in example
    +(#113 by @docteurklein and #114 and #115 by @clue)

    +
  • +
  • +

    Improve test suite by running against Mac OS X on Travis
    +(#112 by @clue)

    +
  • +
+ +
+ +

+ + + Datagram 1.3.0 + + + (2017-09-25) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Always use Resolver with default DNS to match Socket component
    +and update DNS dependency to support hosts file on all platforms
    +(#19 and #20 by @clue)

    +

    This means that connecting to hosts such as localhost (and for example
    +those used for Docker containers) will now work as expected across all
    +platforms with no changes required:

    +
    $factory = new Factory($loop);
    +$factory->createClient('localhost:5353');
    +
  • +
+ +
+ +

+ + + HTTPClient 0.5.6 + + + (2017-09-17) + + Release on GitHub + + +

+ +
    +
  • Feature: Update Socket component to support HTTP over Unix domain sockets (UDS)
    +(#110 by @clue)
  • +
+ +
+ +

+ + + Socket 0.8.4 + + + (2017-09-16) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Add FixedUriConnector decorator to use fixed, preconfigured URI instead
    +(#117 by @clue)

    +

    This can be useful for consumers that do not support certain URIs, such as
    +when you want to explicitly connect to a Unix domain socket (UDS) path
    +instead of connecting to a default address assumed by an higher-level API:

    +
    $connector = new FixedUriConnector(
    +    'unix:///var/run/docker.sock',
    +    new UnixConnector($loop)
    +);
    +
    +// destination will be ignored, actually connects to Unix domain socket
    +$promise = $connector->connect('localhost:80');
    +
  • +
+ +
+ +

+ + + HTTPClient 0.5.5 + + + (2017-09-10) + + Release on GitHub + + +

+ +
    +
  • Fix: Update Socket component to work around sending secure HTTPS requests with PHP < 7.1.4
    +(#109 by @clue)
  • +
+ +
+ +

+ + + Socket 0.8.3 + + + (2017-09-08) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Reduce memory consumption for failed connections
    +(#113 by @valga)

    +
  • +
  • +

    Fix: Work around write chunk size for TLS streams for PHP < 7.1.14
    +(#114 by @clue)

    +
  • +
+ +
+ +

+ + + HTTPClient 0.5.4 + + + (2017-08-25) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Update Socket dependency to support hosts file on all platforms
    +(#108 by @clue)

    +

    This means that HTTP requests to hosts such as localhost will now work as
    +expected across all platforms with no changes required:

    +
    $client = new Client($loop);
    +$request = $client->request('GET', 'http://localhost/');
    +$request->on('response', function (Response $response) {
    +    //
    +});
    +$request->end();
    +
  • +
+ +
+ +

+ + + Socket 0.8.2 + + + (2017-08-25) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Update DNS dependency to support hosts file on all platforms
    +(#112 by @clue)

    +

    This means that connecting to hosts such as localhost will now work as
    +expected across all platforms with no changes required:

    +
    $connector = new Connector($loop);
    +$connector->connect('localhost:8080')->then(function ($connection) {
    +    //
    +});
    +
  • +
+ +
+ +

+ + + DNS 0.4.11 + + + (2017-08-25) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Support resolving from default hosts file
    +(#75, #76 and #77 by @clue)

    +

    This means that resolving hosts such as localhost will now work as
    +expected across all platforms with no changes required:

    +
    $resolver->resolve('localhost')->then(function ($ip) {
    +    echo 'IP: ' . $ip;
    +});
    +

    The new HostsExecutor exists for advanced usage and is otherwise used
    +internally for this feature.

    +
  • +
+ +
+ +

+ + + HTTPClient 0.5.3 + + + (2017-08-16) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Target evenement 3.0 a long side 2.0
    +(#106 by @WyriHaximus)

    +
  • +
  • +

    Improve test suite by locking Travis distro so new defaults will not break the build
    +(#105 by @clue)

    +
  • +
+ +
+ +

+ + + HTTP 0.7.4 + + + (2017-08-16) + + Release on GitHub + + +

+ +
    +
  • Improvement: Target evenement 3.0 a long side 2.0 and 1.0
    +(#212 by @WyriHaximus)
  • +
+ +
+ +

+ + + ChildProcess 0.5.0 + + + (2017-08-15) + + Release on GitHub + + +

+ +
    +
  • Forward compatibility: react/event-loop 1.0 and 0.5, react/stream 0.7.2 and 1.0, and Événement 3.0
    +(#38 and #44 by @WyriHaximus, and #46 by @clue)
  • +
  • Windows compatibility: Documentate that windows isn't supported in 0.5 unless used from within WSL
    +(#41 and #47 by @WyriHaximus)
  • +
  • Documentation: Termination examples
    +(#42 by @clue)
  • +
  • BC: Throw LogicException in Process instanciating when on Windows or when proc_open is missing (was RuntimeException)
    +(#49 by @mdrost)
  • +
+ +
+ +

+ + + Socket 0.8.1 + + + (2017-08-15) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Forward compatibility with upcoming EventLoop v1.0 and v0.5 and
    +target evenement 3.0 a long side 2.0 and 1.0
    +(#104 by @clue and #111 by @WyriHaximus)

    +
  • +
  • +

    Improve test suite by locking Travis distro so new defaults will not break the build and
    +fix HHVM build for now again and ignore future HHVM build errors
    +(#109 and #110 by @clue)

    +
  • +
  • +

    Minor documentation fixes
    +(#103 by @christiaan and #108 by @hansott)

    +
  • +
+ +
+ +

+ + + HTTP 0.7.3 + + + (2017-08-14) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Support Throwable when setting previous exception from server callback
    +(#155 by @jsor)

    +
  • +
  • +

    Fix: Fixed URI parsing for origin-form requests that contain scheme separator
    +such as /path?param=http://example.com.
    +(#209 by @aaronbonneau)

    +
  • +
  • +

    Improve test suite by locking Travis distro so new defaults will not break the build
    +(#211 by @clue)

    +
  • +
+ +
+ +

+ + + DNS 0.4.10 + + + (2017-08-10) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Forward compatibility with EventLoop v1.0 and v0.5 and
    +lock minimum dependencies and work around circular dependency for tests
    +(#70 and #71 by @clue)

    +
  • +
  • +

    Fix: Work around DNS timeout issues for Windows users
    +(#74 by @clue)

    +
  • +
  • +

    Documentation and examples for advanced usage
    +(#66 by @WyriHaximus)

    +
  • +
  • +

    Remove broken TCP code, do not retry with invalid TCP query
    +(#73 by @clue)

    +
  • +
  • +

    Improve test suite by fixing HHVM build for now again and ignore future HHVM build errors and
    +lock Travis distro so new defaults will not break the build and
    +fix failing tests for PHP 7.1
    +(#68 by @WyriHaximus and #69 and #72 by @clue)

    +
  • +
+ +
+ +

+ + + Datagram 1.2.0 + + + (2017-08-09) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Target evenement 3.0 a long side 2.0 and 1.0
    +(#16 by @WyriHaximus)

    +
  • +
  • +

    Feature: Forward compatibility with EventLoop v1.0 and v0.5
    +(#18 by @clue)

    +
  • +
  • +

    Improve test suite by updating Travis build config so new defaults do not break the build
    +(#17 by @clue)

    +
  • +
+ +
+ +

+ + + PromiseTimer 1.2.0 + + + (2017-08-08) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Only start timers if input Promise is still pending and
    +return a settled output promise if the input is already settled.
    +(#25 by @clue)

    +
  • +
  • +

    Feature: Cap minimum timer interval at 1µs across all versions
    +(#23 by @clue)

    +
  • +
  • +

    Feature: Forward compatibility with EventLoop v1.0 and v0.5
    +(#27 by @clue)

    +
  • +
  • +

    Improve test suite by adding PHPUnit to require-dev and
    +lock Travis distro so new defaults will not break the build
    +(#24 and #26 by @clue)

    +
  • +
+ +
+ +

+ + + Stream 0.7.3 + + + (2017-08-05) + + Release on GitHub + + +

+ +
    +
  • Improvement: Support Événement 3.0 a long side 2.0 and 1.0
    +(#108 by @WyriHaximus)
  • +
  • Readme: Corrected loop initialization in usage example
    +(#109 by @pulyavin)
  • +
  • Travis: Lock linux distribution preventing future builds from breaking
    +(#110 by @clue)
  • +
+ +
+ +

+ + + HTTP 0.7.2 + + + (2017-07-04) + + Release on GitHub + + +

+ +
    +
  • +

    Fix: Stricter check for invalid request-line in HTTP requests
    +(#206 by @clue)

    +
  • +
  • +

    Refactor to use HTTP response reason phrases from response object
    +(#205 by @clue)

    +
  • +
+ +
+ +

+ + + HTTPClient 0.5.2 + + + (2017-06-27) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Support passing arrays for request header values
    +(#100 by @clue)

    +
  • +
  • +

    Fix: Fix merging default headers if overwritten with custom case headers
    +(#101 by @clue)

    +
  • +
+ +
+ +

+ + + HTTPClient 0.5.1 + + + (2017-06-18) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Emit error event if request URL is invalid
    +(#99 by @clue)

    +
  • +
  • +

    Feature: Support OPTIONS method with asterisk-form (OPTIONS * HTTP/1.1)
    +(#98 by @clue)

    +
  • +
  • +

    Improve documentation for event semantics
    +(#97 by @clue)

    +
  • +
+ +
+ +

+ + + HTTP 0.7.1 + + + (2017-06-17) + + Release on GitHub + + +

+ +
    +
  • +

    Fix: Fix parsing CONNECT request without Host header
    +(#201 by @clue)

    +
  • +
  • +

    Internal preparation for future PSR-7 UploadedFileInterface
    +(#199 by @WyriHaximus)

    +
  • +
+ +
+ +

+ + + Stream 0.7.2 + + + (2017-06-15) + + Release on GitHub + + +

+ +
    +
  • Bug fix: WritableResourceStream: Close the underlying stream when closing the stream.
    +(#107 by @WyriHaximus)
  • +
+ +
+ +

+ + + HTTP 0.7.0 + + + (2017-05-29) + + Release on GitHub + + +

+ +
    +
  • +

    Feature / BC break: Use PSR-7 (http-message) standard and
    +Request-In-Response-Out-style request handler callback.
    +Pass standard PSR-7 ServerRequestInterface and expect any standard
    +PSR-7 ResponseInterface in return for the request handler callback.
    +(#146 and #152 and #170 by @legionth)

    +
    // old
    +$app = function (Request $request, Response $response) {
    +    $response->writeHead(200, array('Content-Type' => 'text/plain'));
    +    $response->end("Hello world!\n");
    +};
    +
    +// new
    +$app = function (ServerRequestInterface $request) {
    +    return new Response(
    +        200,
    +        array('Content-Type' => 'text/plain'),
    +        "Hello world!\n"
    +    );
    +};
    +

    A Content-Length header will automatically be included if the size can be
    +determined from the response body.
    +(#164 by @maciejmrozinski)

    +

    The request handler callback will automatically make sure that responses to
    +HEAD requests and certain status codes, such as 204 (No Content), never
    +contain a response body.
    +(#156 by @clue)

    +

    The intermediary 100 Continue response will automatically be sent if
    +demanded by a HTTP/1.1 client.
    +(#144 by @legionth)

    +

    The request handler callback can now return a standard Promise if
    +processing the request needs some time, such as when querying a database.
    +Similarly, the request handler may return a streaming response if the
    +response body comes from a ReadableStreamInterface or its size is
    +unknown in advance.

    +
    // old
    +$app = function (Request $request, Response $response) use ($db) {
    +    $db->query()->then(function ($result) use ($response) {
    +        $response->writeHead(200, array('Content-Type' => 'text/plain'));
    +        $response->end($result);
    +    });
    +};
    +
    +// new
    +$app = function (ServerRequestInterface $request) use ($db) {
    +    return $db->query()->then(function ($result) {
    +        return new Response(
    +            200,
    +            array('Content-Type' => 'text/plain'),
    +            $result
    +        );
    +    });
    +};
    +

    Pending promies and response streams will automatically be canceled once the
    +client connection closes.
    +(#187 and #188 by @clue)

    +

    The ServerRequestInterface contains the full effective request URI,
    +server-side parameters, query parameters and parsed cookies values as
    +defined in PSR-7.
    +(#167 by @clue and #174, #175 and #180 by @legionth)

    +
    $app = function (ServerRequestInterface $request) {
    +    return new Response(
    +        200,
    +        array('Content-Type' => 'text/plain'),
    +        $request->getUri()->getScheme()
    +    );
    +};
    +

    Advanced: Support duplex stream response for Upgrade requests such as
    +Upgrade: WebSocket or custom protocols and CONNECT requests
    +(#189 and #190 by @clue)

    +
    +

    Note that the request body will currently not be buffered and parsed by
    +default, which depending on your particilar use-case, may limit
    +interoperability with the PSR-7 (http-message) ecosystem.
    +The provided streaming request body interfaces allow you to perform
    +buffering and parsing as needed in the request handler callback.
    +See also the README and examples for more details.

    +
    +
  • +
  • +

    Feature / BC break: Replace request listener with callback function and
    +use listen() method to support multiple listening sockets
    +(#97 by @legionth and #193 by @clue)

    +
    // old
    +$server = new Server($socket);
    +$server->on('request', $app);
    +
    +// new
    +$server = new Server($app);
    +$server->listen($socket);
    +
  • +
  • +

    Feature: Support the more advanced HTTP requests, such as
    +OPTIONS * HTTP/1.1 (OPTIONS method in asterisk-form),
    +GET http://example.com/path HTTP/1.1 (plain proxy requests in absolute-form),
    +CONNECT example.com:443 HTTP/1.1 (CONNECT proxy requests in authority-form)
    +and sanitize Host header value across all requests.
    +(#157, #158, #161, #165, #169 and #173 by @clue)

    +
  • +
  • +

    Feature: Forward compatibility with Socket v1.0, v0.8, v0.7 and v0.6 and
    +forward compatibility with Stream v1.0 and v0.7
    +(#154, #163, #183, #184 and #191 by @clue)

    +
  • +
  • +

    Feature: Simplify examples to ease getting started and
    +add benchmarking example
    +(#151 and #162 by @clue)

    +
  • +
  • +

    Improve test suite by adding tests for case insensitive chunked transfer
    +encoding and ignoring HHVM test failures until Travis tests work again.
    +(#150 by @legionth and #185 by @clue)

    +
  • +
+ +
+ +

+ + + HTTPClient 0.5.0 + + + (2017-05-22) + + Release on GitHub + + +

+ +
    +
  • +

    Feature / BC break: Replace Factory with simple Client constructor
    +(#85 by @clue)

    +

    The Client now accepts a required LoopInterface and an optional
    +ConnectorInterface. It will now create a default Connector if none
    +has been given.

    +
    // old
    +$dnsResolverFactory = new React\Dns\Resolver\Factory();
    +$dnsResolver = $dnsResolverFactory->createCached('8.8.8.8', $loop);
    +$factory = new React\HttpClient\Factory();
    +$client = $factory->create($loop, $dnsResolver);
    +
    +// new
    +$client = new React\HttpClient\Client($loop);
    +
  • +
  • +

    Feature: Request::close() now cancels pending connection attempt
    +(#91 by @clue)

    +
  • +
  • +

    Feature / BC break: Replace deprecated SocketClient with new Socket component
    +(#74, #84 and #88 by @clue)

    +
  • +
  • +

    Feature / BC break: Consistent stream semantics and forward compatibility with upcoming Stream v1.0
    +(#90 by @clue)

    +
  • +
  • +

    Feature: Forward compatibility with upcoming EventLoop v1.0 and v0.5
    +(#89 by @clue)

    +
  • +
  • +

    Fix: Catch Guzzle parser exception
    +(#82 by @djagya)

    +
  • +
+ +
+ +

+ + + Stream 0.7.1 + + + (2017-05-20) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Add optional $writeChunkSize parameter to limit maximum number of
    +bytes to write at once.
    +(#105 by @clue)

    +
    $stream = new WritableResourceStream(STDOUT, $loop, null, 8192);
    +
  • +
  • +

    Ignore HHVM test failures for now until Travis tests work again
    +(#106 by @clue)

    +
  • +
+ +
+ +

+ + + PromiseStream 0.1.1 + + + (2017-05-15) + + Release on GitHub + + +

+ +
    +
  • Improvement: Forward compatibility with stream 1.0, 0.7, 0.6, and 0.5 (#2 by @WyriHaximus)
  • +
+ +
+ +

+ + + PromiseStream 0.1.0 + + + (2017-05-10) + + Release on GitHub + + +

+ + + +
+ +

+ + + Socket 0.8.0 + + + (2017-05-09) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: New Server class now acts as a facade for existing server classes
    +and renamed old Server to TcpServer for advanced usage.
    +(#96 and #97 by @clue)

    +

    The Server class is now the main class in this package that implements the
    +ServerInterface and allows you to accept incoming streaming connections,
    +such as plaintext TCP/IP or secure TLS connection streams.

    +
    +

    This is not a BC break and consumer code does not have to be updated.

    +
    +
  • +
  • +

    Feature / BC break: All addresses are now URIs that include the URI scheme
    +(#98 by @clue)

    +
    - $parts = parse_url('tcp://' . $conn->getRemoteAddress());
    ++ $parts = parse_url($conn->getRemoteAddress());
    +
  • +
  • +

    Fix: Fix unix:// addresses for Unix domain socket (UDS) paths
    +(#100 by @clue)

    +
  • +
  • +

    Feature: Forward compatibility with Stream v1.0 and v0.7
    +(#99 by @clue)

    +
  • +
+ +
+ +

+ + + Stream 0.7.0 + + + (2017-05-04) + + Release on GitHub + + +

+ +
    +
  • +

    Removed / BC break: Remove deprecated and unneeded functionality
    +(#45, #87, #90, #91 and #93 by @clue)

    +
      +
    • +

      Remove deprecated Stream class, use DuplexResourceStream instead
      +(#87 by @clue)

      +
    • +
    • +

      Remove public $buffer property, use new constructor parameters instead
      +(#91 by @clue)

      +
    • +
    • +

      Remove public $stream property from all resource streams
      +(#90 by @clue)

      +
    • +
    • +

      Remove undocumented and now unused ReadableStream and WritableStream
      +(#93 by @clue)

      +
    • +
    • +

      Remove BufferedSink
      +(#45 by @clue)

      +
    • +
    +
  • +
  • +

    Feature / BC break: Simplify ThroughStream by using data callback instead of
    +inheritance. It is now a direct implementation of DuplexStreamInterface.
    +(#88 and #89 by @clue)

    +
    $through = new ThroughStream(function ($data) {
    +    return json_encode($data) . PHP_EOL;
    +});
    +$through->on('data', $this->expectCallableOnceWith("[2, true]\n"));
    +
    +$through->write(array(2, true));
    +
  • +
  • +

    Feature / BC break: The CompositeStream starts closed if either side is
    +already closed and forwards pause to pipe source on first write attempt.
    +(#96 and #103 by @clue)

    +

    If either side of the composite stream closes, it will also close the other
    +side. We now also ensure that if either side is already closed during
    +instantiation, it will also close the other side.

    +
  • +
  • +

    BC break: Mark all classes as final and
    +mark internal API as private to discourage inheritance
    +(#95 and #99 by @clue)

    +
  • +
  • +

    Feature / BC break: Only emit error event for fatal errors
    +(#92 by @clue)

    +
    +

    The error event was previously also allowed to be emitted for non-fatal
    +errors, but our implementations actually only ever emitted this as a fatal
    +error and then closed the stream.

    +
    +
  • +
  • +

    Feature: Explicitly allow custom events and exclude any semantics
    +(#97 by @clue)

    +
  • +
  • +

    Support legacy PHP 5.3 through PHP 7.1 and HHVM and improve usage documentation
    +(#100 and #102 by @clue)

    +
  • +
  • +

    Actually require all dependencies so this is self-contained and improve
    +forward compatibility with EventLoop v1.0 and v0.5
    +(#94 and #98 by @clue)

    +
  • +
+ +
+ +

+ + + DNS 0.4.9 + + + (2017-05-01) + + Release on GitHub + + +

+ +
    +
  • Feature: Forward compatibility with upcoming Socket v1.0 and v0.8
    +(#61 by @clue)
  • +
+ +
+ +

+ + + EventLoop 0.4.3 + + + (2017-04-27) + + Release on GitHub + + +

+ +

This is a bug fix and improvement release:

+
    +
  • Bug fix: Bugfix in the usage sample code #57 (@dandelionred)
  • +
  • Improvement: Remove branch-alias definition #53 (@WyriHaximus)
  • +
  • Improvement: StreamSelectLoop: Use fresh time so Timers added during stream events are accurate #51 (@andrewminerd)
  • +
  • Improvement: Avoid deprecation warnings in test suite due to deprecation of getMock() in PHPUnit #68 (@martinschroeder)
  • +
  • Improvement: Add PHPUnit 4.8 to require-dev #69 (@shaunbramley)
  • +
  • Improvement: Increase test timeouts for HHVM and unify timeout handling #70 (@clue)
  • +
  • Improvement: Travis improvements (backported from #74) #75 (@clue)
  • +
  • Improvement: Test suite now uses socket pairs instead of memory streams #66 (@martinschroeder)
  • +
  • Improvement: StreamSelectLoop: Test suite uses signal constant names in data provider #67 (@martinschroeder)
  • +
  • Improvement: ExtEventLoop: No longer suppress all errors #65 (@mamciek)
  • +
  • Improvement: Readme cleanup #89 (@jsor)
  • +
  • Improvement: Restructure and improve README #90 (@jsor)
  • +
  • Bug fix: StreamSelectLoop: Fix erroneous zero-time sleep (backport to 0.4) #94 (@jsor)
  • +
+ +
+ +

+ + + Socket 0.7.2 + + + (2017-04-24) + + Release on GitHub + + +

+ +
    +
  • Fix: Work around latest PHP 7.0.18 and 7.1.4 no longer accepting full URIs
    +(#94 by @clue)
  • +
+ +
+ +

+ + + DNS 0.4.8 + + + (2017-04-16) + + Release on GitHub + + +

+ +
    +
  • Feature: Add support for the AAAA record type to the protocol parser
    +(#58 by @othillo)
  • +
  • Feature: Add support for the PTR record type to the protocol parser
    +(#59 by @othillo)
  • +
+ +
+ +

+ + + Socket 0.7.1 + + + (2017-04-10) + + Release on GitHub + + +

+ +
    +
  • Fix: Ignore HHVM errors when closing connection that is already closing
    +(#91 by @clue)
  • +
+ +
+ +

+ + + Socket 0.7.0 + + + (2017-04-10) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Merge SocketClient component into this component
    +(#87 by @clue)

    +

    This means that this package now provides async, streaming plaintext TCP/IP
    +and secure TLS socket server and client connections for ReactPHP.

    +
    $connector = new React\Socket\Connector($loop);
    +$connector->connect('google.com:80')->then(function (ConnectionInterface $conn) {
    +    $connection->write('');
    +});
    +

    Accordingly, the ConnectionInterface is now used to represent both incoming
    +server side connections as well as outgoing client side connections.

    +

    If you've previously used the SocketClient component to establish outgoing
    +client connections, upgrading should take no longer than a few minutes.
    +All classes have been merged as-is from the latest v0.7.0 release with no
    +other changes, so you can simply update your code to use the updated namespace
    +like this:

    +
    // old from SocketClient component and namespace
    +$connector = new React\SocketClient\Connector($loop);
    +$connector->connect('google.com:80')->then(function (ConnectionInterface $conn) {
    +    $connection->write('');
    +});
    +
    +// new
    +$connector = new React\Socket\Connector($loop);
    +$connector->connect('google.com:80')->then(function (ConnectionInterface $conn) {
    +    $connection->write('');
    +});
    +
  • +
+ +
+ +

+ + + Socket 0.6.0 + + + (2017-04-04) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Add LimitingServer to limit and keep track of open connections
    +(#86 by @clue)

    +
    $server = new Server(0, $loop);
    +$server = new LimitingServer($server, 100);
    +
    +$server->on('connection', function (ConnectionInterface $connection) {
    +    $connection->write('hello there!' . PHP_EOL);
    +
    +});
    +
  • +
  • +

    Feature / BC break: Add pause() and resume() methods to limit active
    +connections
    +(#84 by @clue)

    +
    $server = new Server(0, $loop);
    +$server->pause();
    +
    +$loop->addTimer(1.0, function() use ($server) {
    +    $server->resume();
    +});
    +
  • +
+ +
+ +

+ + + DNS 0.4.7 + + + (2017-03-31) + + Release on GitHub + + +

+ +
    +
  • Feature: Forward compatibility with upcoming Socket v0.6 and v0.7 component
    +(#57 by @clue)
  • +
+ +
+ +

+ + + Stream 0.6.0 + + + (2017-03-26) + + Release on GitHub + + +

+ +
    +
  • +

    Feature / Fix / BC break: Add DuplexResourceStream and deprecate Stream
    +(#85 by @clue)

    +
    // old (does still work for BC reasons)
    +$stream = new Stream($connection, $loop);
    +
    +// new
    +$stream = new DuplexResourceStream($connection, $loop);
    +

    Note that the DuplexResourceStream now rejects read-only or write-only
    +streams, so this may affect BC. If you want a read-only or write-only
    +resource, use ReadableResourceStream or WritableResourceStream instead of
    +DuplexResourceStream.

    +
    +

    BC note: This class was previously called Stream. The Stream class still
    +exists for BC reasons and will be removed in future versions of this package.

    +
    +
  • +
  • +

    Feature / BC break: Add WritableResourceStream (previously called Buffer)
    +(#84 by @clue)

    +
    // old
    +$stream = new Buffer(STDOUT, $loop);
    +
    +// new
    +$stream = new WritableResourceStream(STDOUT, $loop);
    +
  • +
  • +

    Feature: Add ReadableResourceStream
    +(#83 by @clue)

    +
    $stream = new ReadableResourceStream(STDIN, $loop);
    +
  • +
  • +

    Fix / BC Break: Enforce using non-blocking I/O
    +(#46 by @clue)

    +
    +

    BC note: This is known to affect process pipes on Windows which do not
    +support non-blocking I/O and could thus block the whole EventLoop previously.

    +
    +
  • +
  • +

    Feature / Fix / BC break: Consistent semantics for
    +DuplexStreamInterface::end() to ensure it SHOULD also end readable side
    +(#86 by @clue)

    +
  • +
  • +

    Fix: Do not use unbuffered reads on pipe streams for legacy PHP < 5.4
    +(#80 by @clue)

    +
  • +
+ +
+ +

+ + + Promise 2.5.1 + + + (2017-03-25) + + Release on GitHub + + +

+ +
    +
  • Fix circular references when resolving with a promise which follows itself (#94).
  • +
+ +
+ +

+ + + HTTPClient 0.4.17 + + + (2017-03-20) + + Release on GitHub + + +

+ +
    +
  • Improvement: Add PHPUnit to require-dev #75 @jsor
  • +
  • Fix: Fix chunk header to be case-insensitive and allow leading zeros for end chunk #77 @mdrost
  • +
+ +
+ +

+ + + ChildProcess 0.4.3 + + + (2017-03-14) + + Release on GitHub + + +

+ +
    +
  • +

    Ease getting started by improving documentation and adding examples
    +(#33 and #34 by @clue)

    +
  • +
  • +

    First class support for PHP 5.3 through PHP 7.1 and HHVM
    +(#29 by @clue and #32 by @WyriHaximus)

    +
  • +
+ +
+ +

+ + + DNS 0.4.6 + + + (2017-03-11) + + Release on GitHub + + +

+ +
    +
  • Fix: Fix DNS timeout issues for Windows users and add forward compatibility
    +with Stream v0.5 and upcoming v0.6
    +(#53 by @clue)
  • +
  • Improve test suite by adding PHPUnit to require-dev
    +(#54 by @clue)
  • +
+ +
+ +

+ + + ChildProcess 0.4.2 + + + (2017-03-10) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Forward compatibility with Stream v0.5
    +(#26 by @clue)

    +
  • +
  • +

    Improve test suite by removing AppVeyor and adding PHPUnit to require-dev
    +(#27 and #28 by @clue)

    +
  • +
+ +
+ +

+ + + HTTP 0.6.0 + + + (2017-03-09) + + Release on GitHub + + +

+ +
    +
  • +

    Feature / BC break: The Request and Response objects now follow strict
    +stream semantics and their respective methods and events.
    +(#116, #129, #133, #135, #136, #137, #138, #140, #141 by @legionth
    +and #122, #123, #130, #131, #132, #142 by @clue)

    +

    This implies that the Server now supports proper detection of the request
    +message body stream, such as supporting decoding chunked transfer encoding,
    +delimiting requests with an explicit Content-Length header
    +and those with an empty request message body.

    +

    These streaming semantics are compatible with previous Stream v0.5, future
    +compatible with v0.5 and upcoming v0.6 versions and can be used like this:

    +
    $http->on('request', function (Request $request, Response $response) {
    +    $contentLength = 0;
    +    $request->on('data', function ($data) use (&$contentLength) {
    +        $contentLength += strlen($data);
    +    });
    +
    +    $request->on('end', function () use ($response, &$contentLength){
    +        $response->writeHead(200, array('Content-Type' => 'text/plain'));
    +        $response->end("The length of the submitted request body is: " . $contentLength);
    +    });
    +
    +    // an error occured
    +    // e.g. on invalid chunked encoded data or an unexpected 'end' event 
    +    $request->on('error', function (\Exception $exception) use ($response, &$contentLength) {
    +        $response->writeHead(400, array('Content-Type' => 'text/plain'));
    +        $response->end("An error occured while reading at length: " . $contentLength);
    +    });
    +});
    +

    Similarly, the Request and Response now strictly follow the
    +close() method and close event semantics.
    +Closing the Request does not interrupt the underlying TCP/IP in
    +order to allow still sending back a valid response message.
    +Closing the Response does terminate the underlying TCP/IP
    +connection in order to clean up resources.

    +

    You should make sure to always attach a request event listener
    +like above. The Server will not respond to an incoming HTTP
    +request otherwise and keep the TCP/IP connection pending until the
    +other side chooses to close the connection.

    +
  • +
  • +

    Feature: Support HTTP/1.1 and HTTP/1.0 for Request and Response.
    +(#124, #125, #126, #127, #128 by @clue and #139 by @legionth)

    +

    The outgoing Response will automatically use the same HTTP version as the
    +incoming Request message and will only apply HTTP/1.1 semantics if
    +applicable. This includes that the Response will automatically attach a
    +Date and Connection: close header if applicable.

    +

    This implies that the Server now automatically responds with HTTP error
    +messages for invalid requests (status 400) and those exceeding internal
    +request header limits (status 431).

    +
  • +
+ +
+ +

+ + + Socket 0.5.1 + + + (2017-03-09) + + Release on GitHub + + +

+ +
    +
  • Feature: Forward compatibility with Stream v0.5 and upcoming v0.6
    +(#79 by @clue)
  • +
+ +
+ +

+ + + Stream 0.5.0 + + + (2017-03-08) + + Release on GitHub + + +

+ +
    +
  • +

    Feature / BC break: Consistent end event semantics (EOF)
    +(#70 by @clue)

    +

    The end event will now only be emitted for a successful end, not if the
    +stream closes due to an unrecoverable error event or if you call close()
    +explicitly.
    +If you want to detect when the stream closes (terminates), use the close
    +event instead.

    +
  • +
  • +

    BC break: Remove custom (undocumented) full-drain event from Buffer
    +(#63 and #68 by @clue)

    +
    +

    The full-drain event was undocumented and mostly used internally.
    +Relying on this event has attracted some low-quality code in the past, so
    +we've removed this from the public API in order to work out a better
    +solution instead.
    +If you want to detect when the buffer finishes flushing data to the stream,
    +you may want to look into its end() method or the close event instead.

    +
    +
  • +
  • +

    Feature / BC break: Consistent event semantics and documentation,
    +explicitly state when events will be emitted and which arguments they
    +receive.
    +(#73 and #69 by @clue)

    +

    The documentation now explicitly defines each event and its arguments.
    +Custom events and event arguments are still supported.
    +Most notably, all defined events only receive inherently required event
    +arguments and no longer transmit the instance they are emitted on for
    +consistency and performance reasons.

    +
    // old (inconsistent and not supported by all implementations)
    +$stream->on('data', function ($data, $stream) {
    +    // process $data
    +});
    +
    +// new (consistent throughout the whole ecosystem)
    +$stream->on('data', function ($data) use ($stream) {
    +    // process $data
    +});
    +
    +

    This mostly adds documentation (and thus some stricter, consistent
    +definitions) for the existing behavior, it does NOT define any major
    +changes otherwise.
    +Most existing code should be compatible with these changes, unless
    +it relied on some undocumented/unintended semantics.

    +
    +
  • +
  • +

    Feature / BC break: Consistent method semantics and documentation
    +(#72 by @clue)

    +
    +

    This mostly adds documentation (and thus some stricter, consistent
    +definitions) for the existing behavior, it does NOT define any major
    +changes otherwise.
    +Most existing code should be compatible with these changes, unless
    +it relied on some undocumented/unintended semantics.

    +
    +
  • +
  • +

    Feature: Consistent pipe() semantics for closed and closing streams
    +(#71 from @clue)

    +

    The source stream will now always be paused via pause() when the
    +destination stream closes. Also, properly stop piping if the source
    +stream closes and remove all event forwarding.

    +
  • +
  • +

    Improve test suite by adding PHPUnit to require-dev and improving coverage.
    +(#74 and #75 by @clue, #66 by @nawarian)

    +
  • +
+ +
+ +

+ + + DNS 0.4.5 + + + (2017-03-02) + + Release on GitHub + + +

+ +
    +
  • Fix: Ensure we ignore the case of the answer
    +(#51 by @WyriHaximus)
  • +
  • Feature: Add TimeoutExecutor and simplify internal APIs to allow internal
    +code re-use for upcoming versions.
    +(#48 and #49 by @clue)
  • +
+ +
+ +

+ + + HTTPClient 0.4.16 + + + (2017-03-01) + + Release on GitHub + + +

+ + + +
+ +

+ + + HTTP 0.5.0 + + + (2017-02-16) + + Release on GitHub + + +

+ +
    +
  • +

    Feature / BC break: Change Request methods to be in line with PSR-7
    +(#117 by @clue)

    +
      +
    • Rename getQuery() to getQueryParams()
    • +
    • Rename getHttpVersion() to getProtocolVersion()
    • +
    • Change getHeaders() to always return an array of string values
      +for each header
    • +
    +
  • +
  • +

    Feature / BC break: Update Socket component to v0.5 and
    +add secure HTTPS server support
    +(#90 and #119 by @clue)

    +
    // old plaintext HTTP server
    +$socket = new React\Socket\Server($loop);
    +$socket->listen(8080, '127.0.0.1');
    +$http = new React\Http\Server($socket);
    +
    +// new plaintext HTTP server
    +$socket = new React\Socket\Server('127.0.0.1:8080', $loop);
    +$http = new React\Http\Server($socket);
    +
    +// new secure HTTPS server
    +$socket = new React\Socket\Server('127.0.0.1:8080', $loop);
    +$socket = new React\Socket\SecureServer($socket, $loop, array(
    +    'local_cert' => __DIR__ . '/localhost.pem'
    +));
    +$http = new React\Http\Server($socket);
    +
  • +
  • +

    BC break: Mark internal APIs as internal or private and
    +remove unneeded ServerInterface
    +(#118 by @clue, #95 by @legionth)

    +
  • +
+ +
+ +

+ + + Socket 0.5.0 + + + (2017-02-14) + + Release on GitHub + + +

+ +
    +
  • +

    Feature / BC break: Replace listen() call with URIs passed to constructor
    +and reject listening on hostnames with InvalidArgumentException
    +and replace ConnectionException with RuntimeException for consistency
    +(#61, #66 and #72 by @clue)

    +
    // old
    +$server = new Server($loop);
    +$server->listen(8080);
    +
    +// new
    +$server = new Server(8080, $loop);
    +

    Similarly, you can now pass a full listening URI to the constructor to change
    +the listening host:

    +
    // old
    +$server = new Server($loop);
    +$server->listen(8080, '127.0.0.1');
    +
    +// new
    +$server = new Server('127.0.0.1:8080', $loop);
    +

    Trying to start listening on (DNS) host names will now throw an
    +InvalidArgumentException, use IP addresses instead:

    +
    // old
    +$server = new Server($loop);
    +$server->listen(8080, 'localhost');
    +
    +// new
    +$server = new Server('127.0.0.1:8080', $loop);
    +

    If trying to listen fails (such as if port is already in use or port below
    +1024 may require root access etc.), it will now throw a RuntimeException,
    +the ConnectionException class has been removed:

    +
    // old: throws React\Socket\ConnectionException
    +$server = new Server($loop);
    +$server->listen(80);
    +
    +// new: throws RuntimeException
    +$server = new Server(80, $loop);
    +
  • +
  • +

    Feature / BC break: Rename shutdown() to close() for consistency throughout React
    +(#62 by @clue)

    +
    // old
    +$server->shutdown();
    +
    +// new
    +$server->close();
    +
  • +
  • +

    Feature / BC break: Replace getPort() with getAddress()
    +(#67 by @clue)

    +
    // old
    +echo $server->getPort(); // 8080
    +
    +// new
    +echo $server->getAddress(); // 127.0.0.1:8080
    +
  • +
  • +

    Feature / BC break: getRemoteAddress() returns full address instead of only IP
    +(#65 by @clue)

    +
    // old
    +echo $connection->getRemoteAddress(); // 192.168.0.1
    +
    +// new
    +echo $connection->getRemoteAddress(); // 192.168.0.1:51743
    +
  • +
  • +

    Feature / BC break: Add getLocalAddress() method
    +(#68 by @clue)

    +
    echo $connection->getLocalAddress(); // 127.0.0.1:8080
    +
  • +
  • +

    BC break: The Server and SecureServer class are now marked final
    +and you can no longer extend them
    +(which was never documented or recommended anyway).
    +Public properties and event handlers are now internal only.
    +Please use composition instead of extension.
    +(#71, #70 and #69 by @clue)

    +
  • +
+ +
+ +

+ + + HTTP 0.4.4 + + + (2017-02-13) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Add request header accessors (à la PSR-7)
    +(#103 by @clue)

    +
    // get value of host header
    +$host = $request->getHeaderLine('Host');
    +
    +// get list of all cookie headers
    +$cookies = $request->getHeader('Cookie');
    +
  • +
  • +

    Feature: Forward pause() and resume() from Request to underlying connection
    +(#110 by @clue)

    +
    // support back-pressure when piping request into slower destination
    +$request->pipe($dest);
    +
    +// manually pause/resume request
    +$request->pause();
    +$request->resume();
    +
  • +
  • +

    Fix: Fix 100-continue to be handled case-insensitive and ignore it for HTTP/1.0.
    +Similarly, outgoing response headers are now handled case-insensitive, e.g
    +we no longer apply chunked transfer encoding with mixed-case Content-Length.
    +(#107 by @clue)

    +
    // now handled case-insensitive
    +$request->expectsContinue();
    +
    +// now works just like properly-cased header
    +$response->writeHead($status, array('content-length' => 0));
    +
  • +
  • +

    Fix: Do not emit empty data events and ignore empty writes in order to
    +not mess up chunked transfer encoding
    +(#108 and #112 by @clue)

    +
  • +
  • +

    Lock and test minimum required dependency versions and support PHPUnit v5
    +(#113, #115 and #114 by @andig)

    +
  • +
+ +
+ +

+ + + DNS 0.4.4 + + + (2017-02-13) + + Release on GitHub + + +

+ +
    +
  • Fix: Fix handling connection and stream errors
    +(#45 by @clue)
  • +
  • Feature: Add examples and forward compatibility with upcoming Socket v0.5 component
    +(#46 and #47 by @clue)
  • +
+ +
+ +

+ + + HTTP 0.4.3 + + + (2017-02-10) + + Release on GitHub + + +

+ +
    +
  • Fix: Do not take start of body into account when checking maximum header size
    +(#88 by @nopolabs)
  • +
  • Fix: Remove data listener if HeaderParser emits an error
    +(#83 by @nick4fake)
  • +
  • First class support for PHP 5.3 through PHP 7 and HHVM
    +(#101 and #102 by @clue, #66 by @WyriHaximus)
  • +
  • Improve test suite by adding PHPUnit to require-dev,
    +improving forward compatibility with newer PHPUnit versions
    +and replacing unneeded test stubs
    +(#92 and #93 by @nopolabs, #100 by @legionth)
  • +
+ +
+ +

+ + + Socket 0.4.6 + + + (2017-01-26) + + Release on GitHub + + +

+ +
    +
  • Feature: Support socket context options passed to Server
    +(#64 by @clue)
  • +
  • Fix: Properly return null for unknown addresses
    +(#63 by @clue)
  • +
  • Improve documentation for ServerInterface and lock test suite requirements
    +(#60 by @clue, #57 by @shaunbramley)
  • +
+ +
+ +

+ + + Stream 0.4.6 + + + (2017-01-25) + + Release on GitHub + + +

+ +
    +
  • Feature: The Buffer can now be injected into the Stream (or be used standalone)
    +(#62 by @clue)
  • +
  • Fix: Forward close event only once for CompositeStream and ThroughStream
    +(#60 by @clue)
  • +
  • Fix: Consistent close event behavior for Buffer
    +(#61 by @clue)
  • +
+ +
+ +

+ + + Datagram 1.1.1 + + + (2017-01-23) + + Release on GitHub + + +

+ +
    +
  • Fix: Properly format IPv6 addresses and return null for unknown addresses
    +(#14 by @clue)
  • +
  • Fix: Skip IPv6 tests if not supported by the system
    +(#15 by @clue)
  • +
+ +
+ +

+ + + Socket 0.4.5 + + + (2017-01-08) + + Release on GitHub + + +

+ +
    +
  • Feature: Add SecureServer for secure TLS connections
    +(#55 by @clue)
  • +
  • Add functional integration tests
    +(#54 by @clue)
  • +
+ +
+

+ + 2016 +

+ + +

+ + + EventLoop 0.3.5 + + + (2016-12-28) + + Release on GitHub + + +

+ +

This is a compatibility release that eases upgrading to the v0.4 release branch.
+You should consider upgrading to the v0.4 release branch.

+
    +
  • Feature: Cap min timer interval at 1µs, thus improving compatibility with v0.4
    +(#47 by @clue)
  • +
+ +
+ +

+ + + PromiseTimer 1.1.1 + + + (2016-12-27) + + Release on GitHub + + +

+ +
    +
  • Improve test suite to use PSR-4 autoloader and proper namespaces.
    +(#21 by @clue)
  • +
+ +
+ +

+ + + Promise 2.5.0 + + + (2016-12-22) + + Release on GitHub + + +

+ +
    +
  • +

    Revert automatic cancellation of pending collection promises once the output promise resolves. This was introduced in 42d86b7 (PR #36, released in v2.3.0) and was both unintended and backward incompatible.

    +

    If you need automatic cancellation, you can use something like:

    +
    function allAndCancel(array $promises)
    +{
    +     return \React\Promise\all($promises)
    +         ->always(function() use ($promises) {
    +             foreach ($promises as $promise) {
    +                 if ($promise instanceof \React\Promise\CancellablePromiseInterface) {
    +                     $promise->cancel();
    +                 }
    +             }
    +        });
    +}
    +
  • +
  • +

    all() and map() functions now preserve the order of the array (#77).

    +
  • +
  • +

    Fix circular references when resolving a promise with itself (#71).

    +
  • +
+ +
+ +

+ + + Socket 0.4.4 + + + (2016-12-19) + + Release on GitHub + + +

+ +
    +
  • Feature / Fix: ConnectionInterface should extend DuplexStreamInterface + documentation
    +(#50 by @clue)
  • +
  • Feature / Fix: Improve test suite and switch to normal stream handler
    +(#51 by @clue)
  • +
  • Feature: Add examples
    +(#49 by @clue)
  • +
+ +
+ +

+ + + HTTPClient 0.4.15 + + + (2016-12-02) + + Release on GitHub + + +

+ +
    +
  • Improvement: Add examples #69 @clue
  • +
  • Fix: Ensure checking for 0 length chunk, when we should check for it #71 @WyriHaximus
  • +
+ +
+ +

+ + + Stream 0.4.5 + + + (2016-11-13) + + Release on GitHub + + +

+ +
    +
  • Feature: Support setting read buffer size to null (infinite)
    +(#42 by @clue)
  • +
  • Fix: Do not emit full-drain event if Buffer is closed during drain event
    +(#55 by @clue)
  • +
  • Vastly improved performance by factor of 10x to 20x.
    +Raise default buffer sizes to 64 KiB and simplify and improve error handling
    +and unneeded function calls.
    +(#53, #55, #56 by @clue)
  • +
+ +
+ +

+ + + HTTP 0.4.2 + + + (2016-11-09) + + Release on GitHub + + +

+ + + +
+ +

+ + + HTTPClient 0.4.14 + + + (2016-10-28) + + Release on GitHub + + +

+ +
    +
  • Fix: Ensure the first bit of body directly after the headers is emitted into the stream #68 @WyriHaximus
  • +
+ +
+ +

+ + + HTTPClient 0.4.13 + + + (2016-10-19) + + Release on GitHub + + +

+ +
    +
  • Fix: Ensure Request emits initial Response data as string #66 @mmelvin0
  • +
+ +
+ +

+ + + HTTPClient 0.4.12 + + + (2016-10-06) + + Release on GitHub + + +

+ +
    +
  • Fix: Changed $stream from DuplexStreamInterface to ReadableStreamInterface in Response constructor #63 @WyriHaximus
  • +
+ +
+ +

+ + + HTTPClient 0.4.11 + + + (2016-09-15) + + Release on GitHub + + +

+ + + +
+ +

+ + + Stream 0.4.4 + + + (2016-08-22) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Emit error event and close Stream when accessing the underlying
    +stream resource fails with a permanent error.
    +(#52 and #40 by @clue, #25 by @lysenkobv)
  • +
  • Bug fix: Do not emit empty data event if nothing has been read (stream reached EOF)
    +(#39 by @clue)
  • +
  • Bug fix: Ignore empty writes to Buffer
    +(#51 by @clue)
  • +
  • Add benchmarking script to measure throughput in CI
    +(#41 by @clue)
  • +
+ +
+ +

+ + + ChildProcess 0.4.1 + + + (2016-08-01) + + Release on GitHub + + +

+ +
    +
  • Standalone component
  • +
  • Test against PHP 7 and HHVM, report test coverage, AppVeyor tests
  • +
  • Fix: Wait for stdout and stderr to close before watching for process exit
    +(#18 by @mbonneau)
  • +
+ +
+ +

+ + + DNS 0.4.3 + + + (2016-08-01) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Allow for cache adapter injection (#38 by @WyriHaximus)

    +
    $factory = new React\Dns\Resolver\Factory();
    +
    +$cache = new MyCustomCacheInstance();
    +$resolver = $factory->createCached('8.8.8.8', $loop, $cache);
    +
  • +
  • +

    Feature: Support Promise cancellation (#35 by @clue)

    +
    $promise = $resolver->resolve('reactphp.org');
    +
    +$promise->cancel();
    +
  • +
+ +
+ +

+ + + Promise 2.4.1 + + + (2016-05-03) + + Release on GitHub + + +

+ +
    +
  • Fix some() not cancelling pending promises when too much input promises reject (16ff799).
  • +
+ +
+ +

+ + + Promise 2.4.0 + + + (2016-03-31) + + Release on GitHub + + +

+ +
    +
  • Support foreign thenables in resolve().
    +Any object that provides a then() method is now assimilated to a trusted promise that follows the state of this thenable (#52).
  • +
  • Fix some() and any() for input arrays containing not enough items (#34).
  • +
+ +
+ +

+ + + Promise 2.3.0 + + + (2016-03-24) + + Release on GitHub + + +

+ +
    +
  • Allow cancellation of promises returned by functions working on promise collections (#36).
  • +
  • Handle \Throwable in the same way as \Exception (#51 by @joshdifabio).
  • +
+ +
+ +

+ + + HTTPClient 0.3.2 + + + (2016-03-24) + + Release on GitHub + + +

+ +
    +
  • Improvement: Broader guzzle/parser version req @cboden
  • +
  • Improvement: Improve forwards compatibility with all supported versions @clue
  • +
+ +
+ +

+ + + HTTPClient 0.4.10 + + + (2016-03-21) + + Release on GitHub + + +

+ +
    +
  • Improvement: Update react/socket-client dependency to all supported versions @clue
  • +
+ +
+ +

+ + + Datagram 1.1.0 + + + (2016-03-19) + + Release on GitHub + + +

+ +
    +
  • Feature: Support promise cancellation (cancellation of underlying DNS lookup)
    +(#12 by @clue)
  • +
  • Fix: Fix error reporting when trying to create invalid sockets
    +(#11 by @clue)
  • +
  • Improve test suite and update dependencies
    +(#7, #8 by @clue)
  • +
+ +
+ +

+ + + HTTPClient 0.4.9 + + + (2016-03-08) + + Release on GitHub + + +

+ +
    +
  • Improvement: PHP 7 memory leak, related to PHP bug 71737 @jmalloc
  • +
  • Improvement: Clean up all listeners when closing request @weichenlin
  • +
+ +
+ +

+ + + EventLoop 0.4.2 + + + (2016-03-08) + + Release on GitHub + + +

+ +
    +
  • Bug fix: No longer error when signals sent to StreamSelectLoop
  • +
  • Support HHVM and PHP7 (@ondrejmirtes, @cebe)
  • +
  • Feature: Added support for EventConfig for ExtEventLoop (@steverhoades)
  • +
  • Bug fix: Fixed an issue loading loop extension libs via autoloader (@czarpino)
  • +
+ +
+ +

+ + + Promise 1.2.1 + + + (2016-03-07) + + Release on GitHub + + +

+ +
    +
  • Fix DeferredPromise to also implement the CancellablePromiseInterface.
  • +
+ +
+ +

+ + + Socket 0.4.3 + + + (2016-03-01) + + Release on GitHub + + +

+ +
    +
  • Suppress errors on stream_socket_accept to prevent PHP from crashing
  • +
  • Support for PHP7 and HHVM
  • +
  • Support PHP 5.3 again
  • +
+ +
+ +

+ + + PromiseTimer 1.1.0 + + + (2016-02-29) + + Release on GitHub + + +

+ +
    +
  • Feature: Support promise cancellation for all timer primitives
    +(#18 by @clue)
  • +
+ +
+ +

+ + + Promise 1.2.0 + + + (2016-02-27) + + Release on GitHub + + +

+ +

This release makes the API more compatible with 2.0 while preserving full backward compatibility.

+
    +
  • Introduce new CancellablePromiseInterface implemented by all promises.
  • +
  • Add new .cancel() method (part of the CancellablePromiseInterface).
  • +
+ +
+ +

+ + + Promise 2.2.2 + + + (2016-02-26) + + Release on GitHub + + +

+ +
    +
  • Fix cancellation handlers called multiple times (#47 by @clue).
  • +
+ +
+ +

+ + + Cache 0.4.1 + + + (2016-02-25) + + Release on GitHub + + +

+ +
    +
  • Repository maintenance, split off from main repo, improve test suite and documentation
  • +
  • First class support for PHP7 and HHVM (#9 by @clue)
  • +
  • Adjust compatibility to 5.3 (#7 by @clue)
  • +
+ +
+ +

+ + + DNS 0.4.2 + + + (2016-02-24) + + Release on GitHub + + +

+ +
    +
  • Repository maintenance, split off from main repo, improve test suite and documentation
  • +
  • First class support for PHP7 and HHVM (#34 by @clue)
  • +
  • Adjust compatibility to 5.3 (#30 by @clue)
  • +
+ +
+

+ + 2015 +

+ + +

+ + + Datagram 1.0.1 + + + (2015-11-13) + + Release on GitHub + + +

+ +
    +
  • Fix: Correct formatting for remote peer address of incoming datagrams when using IPv6
    +(#6 by @WyriHaximus)
  • +
  • Improve test suite for different PHP versions
  • +
+ +
+ +

+ + + Stream 0.4.3 + + + (2015-10-07) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Read buffer to 0 fixes error with libevent and large quantity of I/O (@mbonneau)
  • +
  • Bug fix: No double-write during drain call (@arnaud-lb)
  • +
  • Bug fix: Support HHVM (@clue)
  • +
  • Adjust compatibility to 5.3 (@clue)
  • +
+ +
+ +

+ + + HTTPClient 0.4.8 + + + (2015-10-05) + + Release on GitHub + + +

+ +
    +
  • Improvement: Avoid hiding exceptions thrown in HttpClient\Request error handlers @arnaud-lb
  • +
+ +
+ +

+ + + PromiseTimer 1.0.0 + + + (2015-09-29) + + Release on GitHub + + +

+ +
    +
  • First tagged release
  • +
+ +
+ +

+ + + HTTPClient 0.4.7 + + + (2015-09-24) + + Release on GitHub + + +

+ +
    +
  • Improvement: Set protocol version on request creation @WyriHaximus
  • +
+ +
+ +

+ + + HTTPClient 0.4.6 + + + (2015-09-20) + + Release on GitHub + + +

+ +
    +
  • Improvement: Support explicitly using HTTP/1.1 protocol version @clue
  • +
+ +
+ +

+ + + HTTPClient 0.4.5 + + + (2015-08-31) + + Release on GitHub + + +

+ +
    +
  • Improvement: Replaced the abandoned guzzle/parser with guzzlehttp/psr7 @WyriHaximus
  • +
+ +
+ +

+ + + Promise 2.2.1 + + + (2015-07-03) + + Release on GitHub + + +

+ +
    +
  • Fix stack error when resolving a promise in its own fulfillment or rejection handlers.
  • +
+ +
+ +

+ + + Promise 1.1.0 + + + (2015-07-01) + + Release on GitHub + + +

+ +

This release makes the API more compatible with 2.0 while preserving full backward compatibility.

+
    +
  • Add React\Promise\Promise class.
  • +
  • Move methods of React\Promise\When and React\Promise\Util to functions while keeping the classes as a proxy for BC.
  • +
+ +
+ +

+ + + HTTPClient 0.4.4 + + + (2015-06-16) + + Release on GitHub + + +

+ +
    +
  • Improvement: Emit drain event when the request is ready to receive more data by @arnaud-lb
  • +
+ +
+ +

+ + + HTTPClient 0.4.3 + + + (2015-06-15) + + Release on GitHub + + +

+ +
    +
  • Improvement: Added support for using auth informations from URL by @arnaud-lb
  • +
+ +
+ +

+ + + HTTP 0.4.1 + + + (2015-05-21) + + Release on GitHub + + +

+ +
    +
  • Replaced guzzle/parser with guzzlehttp/psr7 by @cboden
  • +
  • FIX Continue Header by @iannsp
  • +
  • Missing type hint by @marenzo
  • +
+ +
+ +

+ + + HTTPClient 0.4.2 + + + (2015-05-14) + + Release on GitHub + + +

+ +
    +
  • Improvement: Pass Response object on with data emit by @dpovshed
  • +
+ +
+

+ + 2014 +

+ + +

+ + + Promise 2.2.0 + + + (2014-12-30) + + Release on GitHub + + +

+ +

This release introduces the ExtendedPromiseInterface.

+

The ExtendedPromiseInterface extends the PromiseInterface with useful shortcut
+and utility methods which are not part of the Promises/A specification.

+ +
+ +

+ + + HTTPClient 0.4.1 + + + (2014-11-23) + + Release on GitHub + + +

+ +
    +
  • Improvement: Use EventEmitterTrait instead of base class by @cursedcoder
  • +
  • Improvement: Changed Stream to DuplexStreamInterface in Response::__construct by @mbonneau
  • +
+ +
+ +

+ + + Datagram 1.0.0 + + + (2014-10-23) + + Release on GitHub + + +

+ +
    +
  • Initial tagged release
  • +
+
+

This project has been migrated over from clue/datagram
+which has originally been released in January 2013.
+Upgrading from clue/datagram v0.5.0? Use namespace React\Datagram instead of Datagram and you're ready to go!

+
+ +
+ +

+ + + Promise 2.1.0 + + + (2014-10-15) + + Release on GitHub + + +

+ +

Introduce new CancellablePromiseInterface implemented by all promises.

+ +
+ +

+ + + Stream 0.4.2 + + + (2014-09-10) + + Release on GitHub + + +

+ +
    +
  • Added DuplexStreamInterface
  • +
  • Stream sets stream resources to non-blocking
  • +
  • Fixed potential race condition in pipe
  • +
+ +
+ +

+ + + ChildProcess 0.3.0 + + + (2014-07-31) + + Release on GitHub + + +

+ +

Backwards compatibility release for Reach 0.3.x and PHP 5.3 (see #4).

+ +
+ +

+ + + Socket 0.4.2 + + + (2014-05-25) + + Release on GitHub + + +

+ +
    +
  • [Connection] Verify stream is valid resource
  • +
+ +
+ +

+ + + Socket 0.4.1 + + + (2014-04-13) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Check read buffer for data before shutdown signal and end emit (@artydev)
  • +
  • Bug fix: v0.3.4 changes merged for v0.4.1
  • +
+ +
+ +

+ + + DNS 0.4.1 + + + (2014-04-12) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Fixed PSR-4 autoload path ()
  • +
+ +
+ +

+ + + Stream 0.4.1 + + + (2014-03-30) + + Release on GitHub + + +

+ +
    +
  • Bug fix: v0.3.4 changes merged for v0.4.1
  • +
+ +
+ +

+ + + EventLoop 0.4.1 + + + (2014-02-26) + + Release on GitHub + + +

+ +
    +
  • Bug fix: null timeout in StreamSelectLoop causing 100% CPU usage (@clue)
  • +
  • Bug fix: v0.3.4 changes merged for v0.4.1
  • +
+ +
+ +

+ + + Socket 0.3.4 + + + (2014-02-17) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Reset socket to non-blocking after shutting down (PHP bug)
  • +
+ +
+ +

+ + + Stream 0.3.4 + + + (2014-02-16) + + Release on GitHub + + +

+ +
    +
  • Bug fix: [Stream] Fixed 100% CPU spike from non-empty write buffer on closed stream
  • +
+ +
+ +

+ + + EventLoop 0.4.0 + + + (2014-02-02) + + Release on GitHub + + +

+ +
    +
  • Feature: Added EventLoopInterface::nextTick(), implemented in all event loops (@jmalloc)
  • +
  • Feature: Added EventLoopInterface::futureTick(), implemented in all event loops (@jmalloc)
  • +
  • Feature: Added ExtEventLoop implementation using pecl/event (@jmalloc)
  • +
  • BC break: Bump minimum PHP version to PHP 5.4, remove 5.3 specific hacks
  • +
  • BC break: New method: EventLoopInterface::nextTick()
  • +
  • BC break: New method: EventLoopInterface::futureTick()
  • +
  • Dependency: Autoloading and filesystem structure now PSR-4 instead of PSR-0
  • +
+ +
+ +

+ + + Stream 0.4.0 + + + (2014-02-02) + + Release on GitHub + + +

+ +
    +
  • BC break: Bump minimum PHP version to PHP 5.4, remove 5.3 specific hacks
  • +
  • BC break: Update to Evenement 2.0
  • +
  • Dependency: Autoloading and filesystem structure now PSR-4 instead of PSR-0
  • +
+ +
+ +

+ + + Socket 0.4.0 + + + (2014-02-02) + + Release on GitHub + + +

+ +
    +
  • BC break: Bump minimum PHP version to PHP 5.4, remove 5.3 specific hacks
  • +
  • BC break: Update to React/Promise 2.0
  • +
  • BC break: Update to Evenement 2.0
  • +
  • Dependency: Autoloading and filesystem structure now PSR-4 instead of PSR-0
  • +
  • Bump React dependencies to v0.4
  • +
+ +
+ +

+ + + HTTPClient 0.4.0 + + + (2014-02-02) + + Release on GitHub + + +

+ +
    +
  • BC break: Drop unused Response::getBody()
  • +
  • BC break: Bump minimum PHP version to PHP 5.4, remove 5.3 specific hacks
  • +
  • BC break: Remove $loop argument from HttpClient: Client, Request, Response
  • +
  • BC break: Update to React/Promise 2.0
  • +
  • Dependency: Autoloading and filesystem structure now PSR-4 instead of PSR-0
  • +
  • Bump React dependencies to v0.4
  • +
+ +
+ +

+ + + HTTP 0.4.0 + + + (2014-02-02) + + Release on GitHub + + +

+ +
    +
  • BC break: Bump minimum PHP version to PHP 5.4, remove 5.3 specific hacks
  • +
  • BC break: Update to React/Promise 2.0
  • +
  • BC break: Update to Evenement 2.0
  • +
  • Dependency: Autoloading and filesystem structure now PSR-4 instead of PSR-0
  • +
  • Bump React dependencies to v0.4
  • +
+ +
+ +

+ + + DNS 0.4.0 + + + (2014-02-02) + + Release on GitHub + + +

+ +
    +
  • BC break: Bump minimum PHP version to PHP 5.4, remove 5.3 specific hacks
  • +
  • BC break: Update to React/Promise 2.0
  • +
  • Bug fix: Properly resolve CNAME aliases
  • +
  • Dependency: Autoloading and filesystem structure now PSR-4 instead of PSR-0
  • +
  • Bump React dependencies to v0.4
  • +
+ +
+ +

+ + + ChildProcess 0.4.0 + + + (2014-02-02) + + Release on GitHub + + +

+ +
    +
  • Feature: Added ChildProcess to run async child processes within the event loop (@jmikola)
  • +
+ +
+ +

+ + + Cache 0.4.0 + + + (2014-02-02) + + Release on GitHub + + +

+ +
    +
  • BC break: Bump minimum PHP version to PHP 5.4, remove 5.3 specific hacks
  • +
  • BC break: Update to React/Promise 2.0
  • +
  • Dependency: Autoloading and filesystem structure now PSR-4 instead of PSR-0
  • +
+ +
+

+ + 2013 +

+ + +

+ + + Promise 2.0.0 + + + (2013-12-10) + + Release on GitHub + + +

+ +

New major release. The goal was to streamline the API and to make it more compliant with other promise libraries and especially with the new upcoming ES6 promises specification.

+
    +
  • Add standalone Promise class.
  • +
  • Add new React\Promise\race() function.
  • +
  • BC break: Bump minimum PHP version to PHP 5.4.
  • +
  • BC break: Remove ResolverInterface and PromiseInterface from Deferred.
  • +
  • BC break: Change signature of PromiseInterface.
  • +
  • BC break: Remove When and Util classes and move static methods to functions.
  • +
  • BC break: FulfilledPromise and RejectedPromise now throw an exception when initialized with a promise instead of a value/reason.
  • +
  • BC break: React\Promise\Deferred::resolve() and React\Promise\Deferred::reject() no longer return a promise.
  • +
+ +
+ +

+ + + EventLoop 0.3.4 + + + (2013-07-21) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Changed StreamSelectLoop to use non-blocking behavior on tick() (@astephens25)
  • +
+ +
+ +

+ + + Stream 0.3.3 + + + (2013-07-09) + + Release on GitHub + + +

+ +
    +
  • Bug fix: [Stream] Correctly detect closed connections
  • +
+ +
+ +

+ + + Socket 0.3.3 + + + (2013-07-08) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + EventLoop 0.3.3 + + + (2013-07-08) + + Release on GitHub + + +

+ +
    +
  • Bug fix: No error on removing non-existent streams (@clue)
  • +
  • Bug fix: Do not silently remove feof listeners in LibEvLoop
  • +
+ +
+ +

+ + + Stream 0.3.2 + + + (2013-05-10) + + Release on GitHub + + +

+ +
    +
  • Bug fix: [Stream] Make sure CompositeStream is closed properly
  • +
+ +
+ +

+ + + DNS 0.3.2 + + + (2013-04-27) + + Release on GitHub + + +

+ +
    +
  • Feature: Support default port for IPv6 addresses (@clue)
  • +
+ +
+ +

+ + + Socket 0.3.2 + + + (2013-04-26) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + Cache 0.3.2 + + + (2013-04-24) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + Stream 0.3.1 + + + (2013-04-21) + + Release on GitHub + + +

+ +
    +
  • Bug fix: [Stream] Allow any ReadableStreamInterface on BufferedSink::createPromise()
  • +
+ +
+ +

+ + + HTTPClient 0.3.1 + + + (2013-04-21) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Correct requirement for socket-client
  • +
+ +
+ +

+ + + Socket 0.3.1 + + + (2013-04-20) + + Release on GitHub + + +

+ +
    +
  • Feature: Support binding to IPv6 addresses (@clue)
  • +
+ +
+ +

+ + + HTTPClient 0.3.0 + + + (2013-04-14) + + Release on GitHub + + +

+ +
    +
  • BC break: Socket connection handling moved to new SocketClient component
  • +
  • Bump React dependencies to v0.3
  • +
+ +
+ +

+ + + Stream 0.3.0 + + + (2013-04-14) + + Release on GitHub + + +

+ +
    +
  • Feature: [Stream] Factory method for BufferedSink
  • +
+ +
+ +

+ + + Promise 1.0.4 + + + (2013-04-03) + + Release on GitHub + + +

+ +
    +
  • Trigger PHP errors when invalid callback is passed.
  • +
  • Fully resolve rejection value before calling rejection handler.
  • +
  • Add When::lazy() to create lazy promises which will be initialized once a consumer calls the then() method.
  • +
+ +
+ +

+ + + HTTP 0.3.0 + + + (2013-02-24) + + Release on GitHub + + +

+ +
    +
  • Bump React dependencies to v0.3
  • +
+ +
+ +

+ + + Socket 0.3.0 + + + (2013-01-21) + + Release on GitHub + + +

+ +
    +
  • Bump React dependencies to v0.3
  • +
+ +
+ +

+ + + DNS 0.3.0 + + + (2013-01-20) + + Release on GitHub + + +

+ +
    +
  • Bump React dependencies to v0.3
  • +
+ +
+ +

+ + + Cache 0.3.0 + + + (2013-01-20) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + EventLoop 0.3.0 + + + (2013-01-14) + + Release on GitHub + + +

+ +
    +
  • BC break: New timers API (@nrk)
  • +
  • BC break: Remove check on return value from stream callbacks (@nrk)
  • +
+ +
+ +

+ + + EventLoop 0.2.7 + + + (2013-01-05) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Fix libevent timers with PHP 5.3
  • +
  • Bug fix: Fix libevent timer cancellation (@nrk)
  • +
+ +
+

+ + 2012 +

+ + +

+ + + HTTPClient 0.2.6 + + + (2012-12-26) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + DNS 0.2.6 + + + (2012-12-26) + + Release on GitHub + + +

+ +
    +
  • Feature: New cache component, used by DNS
  • +
+ +
+ +

+ + + EventLoop 0.2.6 + + + (2012-12-26) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Plug memory issue in libevent timers (@cameronjacobson)
  • +
  • Bug fix: Correctly pause LibEvLoop on stop()
  • +
+ +
+ +

+ + + HTTP 0.2.6 + + + (2012-12-26) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Emit end event when Response closes (@beaucollins)
  • +
+ +
+ +

+ + + Cache 0.2.6 + + + (2012-12-24) + + Release on GitHub + + +

+ +
    +
  • Feature: New cache component, used by DNS
  • +
+ +
+ +

+ + + Stream 0.2.6 + + + (2012-12-14) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + Socket 0.2.6 + + + (2012-12-14) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + HTTPClient 0.2.5 + + + (2012-11-26) + + Release on GitHub + + +

+ +
    +
  • Feature: Use a promise-based API internally
  • +
  • Bug fix: Use DNS resolver correctly
  • +
+ +
+ +

+ + + DNS 0.2.5 + + + (2012-11-19) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + Stream 0.2.5 + + + (2012-11-19) + + Release on GitHub + + +

+ +
    +
  • Feature: Make BufferedSink trigger progress events on the promise (@jsor)
  • +
+ +
+ +

+ + + Stream 0.2.4 + + + (2012-11-18) + + Release on GitHub + + +

+ +
    +
  • Feature: Added ThroughStream, CompositeStream, ReadableStream and WritableStream
  • +
  • Feature: Added BufferedSink
  • +
+ +
+ +

+ + + Promise 1.0.3 + + + (2012-11-17) + + Release on GitHub + + +

+ +
    +
  • Add PromisorInterface for objects that have a promise() method.
  • +
+ +
+ +

+ + + DNS 0.2.4 + + + (2012-11-17) + + Release on GitHub + + +

+ +
    +
  • Feature: Change to promise-based API (@jsor)
  • +
+ +
+ +

+ + + Promise 1.0.2 + + + (2012-11-14) + + Release on GitHub + + +

+ +
    +
  • Fix bug in When::any() not correctly unwrapping to a single result value
  • +
  • $promiseOrValue argument of When::resolve() and When::reject() is now optional
  • +
+ +
+ +

+ + + Promise 1.0.1 + + + (2012-11-13) + + Release on GitHub + + +

+ +
    +
  • Prevent deep recursion which was reaching xdebug.max_nesting_level default of 100
  • +
+ +
+ +

+ + + EventLoop 0.2.3 + + + (2012-11-12) + + Release on GitHub + + +

+ +
    +
  • Feature: LibEvLoop, integration of php-libev
  • +
+ +
+ +

+ + + HTTP 0.2.3 + + + (2012-11-10) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Forward drain events from HTTP response (@cs278)
  • +
  • Dependency: Updated guzzle deps to 3.0.*
  • +
+ +
+ +

+ + + Promise 1.0.0 + + + (2012-11-07) + + Release on GitHub + + +

+ +
    +
  • First tagged release
  • +
+ +
+ +

+ + + Stream 0.2.3 + + + (2012-11-05) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + Socket 0.2.3 + + + (2012-11-05) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + HTTPClient 0.2.3 + + + (2012-11-05) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + HTTPClient 0.2.2 + + + (2012-10-28) + + Release on GitHub + + +

+ + + +
+ +

+ + + HTTP 0.2.2 + + + (2012-10-28) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + Stream 0.2.2 + + + (2012-10-28) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + DNS 0.2.3 + + + (2012-10-24) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + DNS 0.2.2 + + + (2012-10-24) + + Release on GitHub + + +

+ + + +
+ +

+ + + Stream 0.2.1 + + + (2012-10-13) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Check for EOF in Buffer::write()
  • +
+ +
+ +

+ + + HTTP 0.2.1 + + + (2012-10-02) + + Release on GitHub + + +

+ +
    +
  • Feature: Support HTTP 1.1 continue
  • +
+ +
+ +

+ + + DNS 0.2.1 + + + (2012-09-24) + + Release on GitHub + + +

+ +
    +
  • Minor adjustments to DNS parser
  • +
+ +
+ +

+ + + Stream 0.2.0 + + + (2012-09-10) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + DNS 0.2.0 + + + (2012-09-10) + + Release on GitHub + + +

+ +
    +
  • Feature: DNS resolver
  • +
+ +
+ +

+ + + Socket 0.2.0 + + + (2012-09-10) + + Release on GitHub + + +

+ +
    +
  • Bump React dependencies to v0.2
  • +
+ +
+ +

+ + + HTTP 0.2.0 + + + (2012-09-10) + + Release on GitHub + + +

+ +
    +
  • Bump React dependencies to v0.2
  • +
+ +
+ +

+ + + EventLoop 0.2.0 + + + (2012-09-10) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + Stream 0.1.1 + + + (2012-07-12) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Testing and functional against PHP >= 5.3.3 and <= 5.3.8
  • +
+ +
+ +

+ + + Socket 0.1.1 + + + (2012-07-12) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + HTTP 0.1.1 + + + (2012-07-12) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + EventLoop 0.1.1 + + + (2012-07-12) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + EventLoop 0.1.0 + + + (2012-07-11) + + Release on GitHub + + +

+ +
    +
  • First tagged release
  • +
+ +
+ +

+ + + Stream 0.1.0 + + + (2012-07-11) + + Release on GitHub + + +

+ +
    +
  • First tagged release
  • +
+ +
+ +

+ + + Socket 0.1.0 + + + (2012-07-11) + + Release on GitHub + + +

+ +
    +
  • First tagged release
  • +
+ +
+ +

+ + + HTTP 0.1.0 + + + (2012-07-11) + + Release on GitHub + + +

+ +
    +
  • First tagged release
  • +
+ +
+
+
+ + + + + + + diff --git a/child-process/changelog.html b/child-process/changelog.html new file mode 100644 index 000000000..0b18a815e --- /dev/null +++ b/child-process/changelog.html @@ -0,0 +1,622 @@ + + + + + + + + ChildProcess: Changelog - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

ChildProcess Changelog

+ + + +

+ + 2018 +

+ + +

+ + + 0.5.2 + + + (2018-01-18) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Detect "exit" immediately if last process pipe is closed
    +(#58 by @clue)

    +

    This introduces a simple check to see if the program is already known to be
    +closed when the last process pipe is closed instead of relying on a periodic
    +timer. This simple change improves "exit" detection significantly for most
    +programs and does not cause a noticeable penalty for more advanced use cases.

    +
  • +
  • +

    Fix forward compatibility with upcoming EventLoop releases
    +(#56 by @clue)

    +
  • +
+ +
+

+ + 2017 +

+ + +

+ + + 0.5.1 + + + (2017-12-22) + + Release on GitHub + + +

+ +
    +
  • +

    Fix: Update Stream dependency to work around SEGFAULT in legacy PHP < 5.4.28
    +and PHP < 5.5.12
    +(#50 and #52 by @clue)

    +
  • +
  • +

    Improve test suite by simplifying test bootstrapping logic via Composer and
    +adding forward compatibility with PHPUnit 6
    +(#53, #54 and #55 by @clue)

    +
  • +
+ +
+ +

+ + + 0.5.0 + + + (2017-08-15) + + Release on GitHub + + +

+ +
    +
  • Forward compatibility: react/event-loop 1.0 and 0.5, react/stream 0.7.2 and 1.0, and Événement 3.0
    +(#38 and #44 by @WyriHaximus, and #46 by @clue)
  • +
  • Windows compatibility: Documentate that windows isn't supported in 0.5 unless used from within WSL
    +(#41 and #47 by @WyriHaximus)
  • +
  • Documentation: Termination examples
    +(#42 by @clue)
  • +
  • BC: Throw LogicException in Process instanciating when on Windows or when proc_open is missing (was RuntimeException)
    +(#49 by @mdrost)
  • +
+ +
+ +

+ + + 0.4.3 + + + (2017-03-14) + + Release on GitHub + + +

+ +
    +
  • +

    Ease getting started by improving documentation and adding examples
    +(#33 and #34 by @clue)

    +
  • +
  • +

    First class support for PHP 5.3 through PHP 7.1 and HHVM
    +(#29 by @clue and #32 by @WyriHaximus)

    +
  • +
+ +
+ +

+ + + 0.4.2 + + + (2017-03-10) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Forward compatibility with Stream v0.5
    +(#26 by @clue)

    +
  • +
  • +

    Improve test suite by removing AppVeyor and adding PHPUnit to require-dev
    +(#27 and #28 by @clue)

    +
  • +
+ +
+

+ + 2016 +

+ + +

+ + + 0.4.1 + + + (2016-08-01) + + Release on GitHub + + +

+ +
    +
  • Standalone component
  • +
  • Test against PHP 7 and HHVM, report test coverage, AppVeyor tests
  • +
  • Fix: Wait for stdout and stderr to close before watching for process exit
    +(#18 by @mbonneau)
  • +
+ +
+

+ + 2014 +

+ + +

+ + + 0.3.0 + + + (2014-07-31) + + Release on GitHub + + +

+ +

Backwards compatibility release for Reach 0.3.x and PHP 5.3 (see #4).

+ +
+ +

+ + + 0.4.0 + + + (2014-02-02) + + Release on GitHub + + +

+ +
    +
  • Feature: Added ChildProcess to run async child processes within the event loop (@jmikola)
  • +
+ +
+
+ +
+
+
+ + + + + + diff --git a/child-process/index.html b/child-process/index.html new file mode 100644 index 000000000..6ad568e77 --- /dev/null +++ b/child-process/index.html @@ -0,0 +1,670 @@ + + + + + + + + ChildProcess: +Child Process - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

ChildProcess

+ + +

Build Status

+

Event-driven library for executing child processes with +ReactPHP.

+

This library integrates Program Execution +with the EventLoop. +Child processes launched may be signaled and will emit an +exit event upon termination. +Additionally, process I/O streams (i.e. STDIN, STDOUT, STDERR) are exposed +as Streams.

+

Table of contents

+ +

+Quickstart example

+
$loop = React\EventLoop\Factory::create();
+
+$process = new React\ChildProcess\Process('echo foo');
+$process->start($loop);
+
+$process->stdout->on('data', function ($chunk) {
+    echo $chunk;
+});
+
+$process->on('exit', function($exitCode, $termSignal) {
+    echo 'Process exited with code ' . $exitCode . PHP_EOL;
+});
+
+$loop->run();
+

See also the examples.

+

+Process

+

+Stream Properties

+

Once a process is started, its I/O streams will be constructed as instances of +React\Stream\ReadableStreamInterface and React\Stream\WritableStreamInterface. +Before start() is called, these properties are null.Once a process terminates, +the streams will become closed but not unset.

+
    +
  • $stdin
  • +
  • $stdout
  • +
  • $stderr
  • +
+

Each of these implement the underlying +ReadableStreamInterface or +WritableStreamInterface and +you can use any of their events and methods as usual:

+
$process->stdout->on('data', function ($chunk) {
+    echo $chunk;
+});
+
+$process->stdout->on('end', function () {
+    echo 'ended';
+});
+
+$process->stdout->on('error', function (Exception $e) {
+    echo 'error: ' . $e->getMessage();
+});
+
+$process->stdout->on('close', function () {
+    echo 'closed';
+});
+
+$process->stdin->write($data);
+$process->stdin->end($data = null);
+//
+

For more details, see the +ReadableStreamInterface and +WritableStreamInterface.

+

+Command

+

The Process class allows you to pass any kind of command line string:

+
$process = new Process('echo test');
+$process->start($loop);
+

By default, PHP will launch processes by wrapping the given command line string +in a sh command, so that the above example will actually execute +sh -c echo test under the hood.

+

This is a very useful feature because it does not only allow you to pass single +commands, but actually allows you to pass any kind of shell command line and +launch multiple sub-commands using command chains (with &&, ||, ; and +others) and allows you to redirect STDIO streams (with 2>&1 and family). +This can be used to pass complete command lines and receive the resulting STDIO +streams from the wrapping shell command like this:

+
$process = new Process('echo run && demo || echo failed');
+$process->start($loop);
+

In other words, the underlying shell is responsible for managing this command +line and launching the individual sub-commands and connecting their STDIO +streams as appropriate. +This implies that the Process class will only receive the resulting STDIO +streams from the wrapping shell, which will thus contain the complete +input/output with no way to discern the input/output of single sub-commands.

+

If you want to discern the output of single sub-commands, you may want to +implement some higher-level protocol logic, such as printing an explicit +boundary between each sub-command like this:

+
$process = new Process('cat first && echo --- && cat second');
+$process->start($loop);
+

As an alternative, considering launching one process at a time and listening on +its exit event to conditionally start the next process in the chain. +This will give you an opportunity to configure the subsequent process I/O streams:

+
$first = new Process('cat first');
+$first->start($loop);
+
+$first->on('exit', function () use ($loop) {
+    $second = new Process('cat second');
+    $second->start($loop);
+});
+

Keep in mind that PHP uses the shell wrapper for ALL command lines. +While this may seem reasonable for more complex command lines, this actually +also applies to running the most simple single command:

+
$process = new Process('yes');
+$process->start($loop);
+

This will actually spawn a command hierarchy similar to this:

+
5480 … \_ php example.php
+5481 …    \_ sh -c yes
+5482 …        \_ yes
+
+

This means that trying to get the underlying process PID or sending signals +will actually target the wrapping shell, which may not be the desired result +in many cases.

+

If you do not want this wrapping shell process to show up, you can simply +prepend the command string with exec, which will cause the wrapping shell +process to be replaced by our process:

+
$process = new Process('exec yes');
+$process->start($loop);
+

This will show a resulting command hierarchy similar to this:

+
5480 … \_ php example.php
+5481 …    \_ yes
+
+

This means that trying to get the underlying process PID and sending signals +will now target the actual command as expected.

+

Note that in this case, the command line will not be run in a wrapping shell. +This implies that when using exec, there's no way to pass command lines such +as those containing command chains or redirected STDIO streams.

+

As a rule of thumb, most commands will likely run just fine with the wrapping +shell. +If you pass a complete command line (or are unsure), you SHOULD most likely keep +the wrapping shell. +If you want to pass an invidual command only, you MAY want to consider +prepending the command string with exec to avoid the wrapping shell.

+

+Termination

+

The exit event will be emitted whenever the process is no longer running. +Event listeners will receive the exit code and termination signal as two +arguments:

+
$process = new Process('sleep 10');
+$process->start($loop);
+
+$process->on('exit', function ($code, $term) {
+    if ($term === null) {
+        echo 'exit with code ' . $code . PHP_EOL;
+    } else {
+        echo 'terminated with signal ' . $term . PHP_EOL;
+    }
+});
+

Note that $code is null if the process has terminated, but the exit +code could not be determined (for example +sigchild compatibility was disabled). +Similarly, $term is null unless the process has terminated in response to +an uncaught signal sent to it. +This is not a limitation of this project, but actual how exit codes and signals +are exposed on POSIX systems, for more details see also +here.

+

It's also worth noting that process termination depends on all file descriptors +being closed beforehand. +This means that all process pipes will emit a close +event before the exit event and that no more data events will arrive after +the exit event. +Accordingly, if either of these pipes is in a paused state (pause() method +or internally due to a pipe() call), this detection may not trigger.

+

The terminate(?int $signal = null): bool method can be used to send the +process a signal (SIGTERM by default). +Depending on which signal you send to the process and whether it has a signal +handler registered, this can be used to either merely signal a process or even +forcefully terminate it.

+
$process->terminate(SIGUSR1);
+

Keep the above section in mind if you want to forcefully terminate a process. +If your process spawn sub-processes or implicitly uses the +wrapping shell mentioned above, its file descriptors may be +inherited to child processes and terminating the main process may not +necessarily terminate the whole process tree. +It is highly suggested that you explicitly close() all process pipes +accordingly when terminating a process:

+
$process = new Process('sleep 10');
+$process->start($loop);
+
+$loop->addTimer(2.0, function () use ($process) {
+    $process->stdin->close();
+    $process->stout->close();
+    $process->stderr->close();
+    $process->terminate(SIGKILL);
+});
+

For many simple programs these seamingly complicated steps can also be avoided +by prefixing the command line with exec to avoid the wrapping shell and its +inherited process pipes as mentioned above.

+
$process = new Process('exec sleep 10');
+$process->start($loop);
+
+$loop->addTimer(2.0, function () use ($process) {
+    $process->terminate();
+});
+

Many command line programs also wait for data on STDIN and terminate cleanly +when this pipe is closed. +For example, the following can be used to "soft-close" a cat process:

+
$process = new Process('cat');
+$process->start($loop);
+
+$loop->addTimer(2.0, function () use ($process) {
+    $process->stdin->end();
+});
+

While process pipes and termination may seem confusing to newcomers, the above +properties actually allow some fine grained control over process termination, +such as first trying a soft-close and then applying a force-close after a +timeout.

+

+Sigchild Compatibility

+

When PHP has been compiled with the --enabled-sigchild option, a child +process' exit code cannot be reliably determined via proc_close() or +proc_get_status(). Instead, we execute the child process with a fourth pipe +and use that to retrieve its exit code.

+

This behavior is used by default and only when necessary. It may be manually +disabled by calling setEnhanceSigchildCompatibility(false) on the Process +before it is started, in which case the exit event may receive null instead +of the actual exit code.

+

Note: This functionality was taken from Symfony's +Process compoment.

+

+Windows Compatibility

+

Due to the blocking nature of STDIN/STDOUT/STDERR pipes on Windows we can +not guarantee this package works as expected on Windows directly. As such when +instantiating Process it throws an exception when on native Windows. +However this package does work on Windows Subsystem for Linux +(or WSL) without issues. We suggest installing WSL +when you want to run this package on Windows.

+

+Install

+

The recommended way to install this library is through Composer. +New to Composer?

+

This will install the latest supported version:

+
$ composer require react/child-process:^0.5.2
+

See also the CHANGELOG for details about version upgrades.

+

This project aims to run on any platform and thus does not require any PHP +extensions and supports running on legacy PHP 5.3 through current PHP 7+ and HHVM. +It's highly recommended to use PHP 7+ for this project.

+

See above note for limited Windows Compatibility.

+

+Tests

+

To run the test suite, you first need to clone this repo and then install all +dependencies through Composer:

+
$ composer install
+

To run the test suite, go to the project root and run:

+
$ php vendor/bin/phpunit
+

+License

+

MIT, see LICENSE file.

+
+ +
+
+
+ + + + + + diff --git a/child-process/license.html b/child-process/license.html new file mode 100644 index 000000000..b85406224 --- /dev/null +++ b/child-process/license.html @@ -0,0 +1,417 @@ + + + + + + + + ChildProcess: License - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

ChildProcess License

+ +

Copyright (c) 2012 Igor Wiedler, Chris Boden

+

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions:

+

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.

+
+ +
+
+
+ + + + + + diff --git a/datagram/changelog.html b/datagram/changelog.html new file mode 100644 index 000000000..09a9c8e43 --- /dev/null +++ b/datagram/changelog.html @@ -0,0 +1,591 @@ + + + + + + + + Datagram: Changelog - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

Datagram Changelog

+ + + +

+ + 2018 +

+ + +

+ + + 1.4.0 + + + (2018-02-28) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Update DNS dependency to support loading system default DNS
    +nameserver config on all supported platforms
    +(/etc/resolv.conf on Unix/Linux/Mac/Docker/WSL and WMIC on Windows)
    +(#23 by @clue)

    +

    This means that connecting to hosts that are managed by a local DNS server,
    +such as a corporate DNS server or when using Docker containers, will now
    +work as expected across all platforms with no changes required:

    +
    $factory = new Factory($loop);
    +$factory->createClient('intranet.example:5353');
    +
  • +
  • +

    Improve README
    +(#22 by @jsor)

    +
  • +
+ +
+

+ + 2017 +

+ + +

+ + + 1.3.0 + + + (2017-09-25) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Always use Resolver with default DNS to match Socket component
    +and update DNS dependency to support hosts file on all platforms
    +(#19 and #20 by @clue)

    +

    This means that connecting to hosts such as localhost (and for example
    +those used for Docker containers) will now work as expected across all
    +platforms with no changes required:

    +
    $factory = new Factory($loop);
    +$factory->createClient('localhost:5353');
    +
  • +
+ +
+ +

+ + + 1.2.0 + + + (2017-08-09) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Target evenement 3.0 a long side 2.0 and 1.0
    +(#16 by @WyriHaximus)

    +
  • +
  • +

    Feature: Forward compatibility with EventLoop v1.0 and v0.5
    +(#18 by @clue)

    +
  • +
  • +

    Improve test suite by updating Travis build config so new defaults do not break the build
    +(#17 by @clue)

    +
  • +
+ +
+ +

+ + + 1.1.1 + + + (2017-01-23) + + Release on GitHub + + +

+ +
    +
  • Fix: Properly format IPv6 addresses and return null for unknown addresses
    +(#14 by @clue)
  • +
  • Fix: Skip IPv6 tests if not supported by the system
    +(#15 by @clue)
  • +
+ +
+

+ + 2016 +

+ + +

+ + + 1.1.0 + + + (2016-03-19) + + Release on GitHub + + +

+ +
    +
  • Feature: Support promise cancellation (cancellation of underlying DNS lookup)
    +(#12 by @clue)
  • +
  • Fix: Fix error reporting when trying to create invalid sockets
    +(#11 by @clue)
  • +
  • Improve test suite and update dependencies
    +(#7, #8 by @clue)
  • +
+ +
+

+ + 2015 +

+ + +

+ + + 1.0.1 + + + (2015-11-13) + + Release on GitHub + + +

+ +
    +
  • Fix: Correct formatting for remote peer address of incoming datagrams when using IPv6
    +(#6 by @WyriHaximus)
  • +
  • Improve test suite for different PHP versions
  • +
+ +
+

+ + 2014 +

+ + +

+ + + 1.0.0 + + + (2014-10-23) + + Release on GitHub + + +

+ +
    +
  • Initial tagged release
  • +
+
+

This project has been migrated over from clue/datagram
+which has originally been released in January 2013.
+Upgrading from clue/datagram v0.5.0? Use namespace React\Datagram instead of Datagram and you're ready to go!

+
+ +
+
+ +
+
+
+ + + + + + diff --git a/datagram/index.html b/datagram/index.html new file mode 100644 index 000000000..8410eba7b --- /dev/null +++ b/datagram/index.html @@ -0,0 +1,423 @@ + + + + + + + + Datagram: +Datagram - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

Datagram

+ + +

Build Status

+

Event-driven UDP datagram socket client and server for ReactPHP.

+

+Quickstart example

+

Once installed, you can use the following code to connect to an UDP server listening on +localhost:1234 and send and receive UDP datagrams:

+
$loop = React\EventLoop\Factory::create();
+$factory = new React\Datagram\Factory($loop);
+
+$factory->createClient('localhost:1234')->then(function (React\Datagram\Socket $client) {
+    $client->send('first');
+
+    $client->on('message', function($message, $serverAddress, $client) {
+        echo 'received "' . $message . '" from ' . $serverAddress. PHP_EOL;
+    });
+});
+
+$loop->run();
+

See also the examples.

+

+Usage

+

This library's API is modelled after node.js's API for +UDP / Datagram Sockets (dgram.Socket).

+

+Install

+

The recommended way to install this library is through Composer. +New to Composer?

+

This project follows SemVer. +This will install the latest supported version:

+
$ composer require react/datagram:^1.4
+

See also the CHANGELOG for details about version upgrades.

+

This project aims to run on any platform and thus does not require any PHP +extensions and supports running on legacy PHP 5.3 through current PHP 7+ and +HHVM. +It's highly recommended to use PHP 7+ for this project.

+

+Tests

+

To run the test suite, you first need to clone this repo and then install all +dependencies through Composer:

+
$ composer install
+

To run the test suite, go to the project root and run:

+
$ php vendor/bin/phpunit
+

+License

+

MIT, see LICENSE file.

+
+ +
+
+
+ + + + + + diff --git a/datagram/license.html b/datagram/license.html new file mode 100644 index 000000000..c729bffdc --- /dev/null +++ b/datagram/license.html @@ -0,0 +1,393 @@ + + + + + + + + Datagram: License - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

Datagram License

+ +

The MIT License (MIT)

+

Copyright (c) 2013 Christian Lück

+

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions:

+

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.

+
+ +
+
+
+ + + + + + diff --git a/dns/changelog.html b/dns/changelog.html new file mode 100644 index 000000000..199cc7ff2 --- /dev/null +++ b/dns/changelog.html @@ -0,0 +1,1034 @@ + + + + + + + + DNS: Changelog - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

DNS Changelog

+ + + +

+ + 2018 +

+ + +

+ + + 0.4.13 + + + (2018-02-27) + + Release on GitHub + + +

+ +
    +
  • +

    Add Config::loadSystemConfigBlocking() to load default system config
    +and support parsing DNS config on all supported platforms
    +(/etc/resolv.conf on Unix/Linux/Mac and WMIC on Windows)
    +(#92, #93, #94 and #95 by @clue)

    +
    $config = Config::loadSystemConfigBlocking();
    +$server = $config->nameservers ? reset($config->nameservers) : '8.8.8.8';
    +
  • +
  • +

    Remove unneeded cyclic dependency on react/socket
    +(#96 by @clue)

    +
  • +
+ +
+ +

+ + + 0.4.12 + + + (2018-01-14) + + Release on GitHub + + +

+ +
    +
  • Improve test suite by adding forward compatibility with PHPUnit 6,
    +test against PHP 7.2, fix forward compatibility with upcoming EventLoop releases,
    +add test group to skip integration tests relying on internet connection
    +and add minor documentation improvements.
    +(#85 and #87 by @carusogabriel, #88 and #89 by @clue and #83 by @jsor)
  • +
+ +
+

+ + 2017 +

+ + +

+ + + 0.4.11 + + + (2017-08-25) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Support resolving from default hosts file
    +(#75, #76 and #77 by @clue)

    +

    This means that resolving hosts such as localhost will now work as
    +expected across all platforms with no changes required:

    +
    $resolver->resolve('localhost')->then(function ($ip) {
    +    echo 'IP: ' . $ip;
    +});
    +

    The new HostsExecutor exists for advanced usage and is otherwise used
    +internally for this feature.

    +
  • +
+ +
+ +

+ + + 0.4.10 + + + (2017-08-10) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Forward compatibility with EventLoop v1.0 and v0.5 and
    +lock minimum dependencies and work around circular dependency for tests
    +(#70 and #71 by @clue)

    +
  • +
  • +

    Fix: Work around DNS timeout issues for Windows users
    +(#74 by @clue)

    +
  • +
  • +

    Documentation and examples for advanced usage
    +(#66 by @WyriHaximus)

    +
  • +
  • +

    Remove broken TCP code, do not retry with invalid TCP query
    +(#73 by @clue)

    +
  • +
  • +

    Improve test suite by fixing HHVM build for now again and ignore future HHVM build errors and
    +lock Travis distro so new defaults will not break the build and
    +fix failing tests for PHP 7.1
    +(#68 by @WyriHaximus and #69 and #72 by @clue)

    +
  • +
+ +
+ +

+ + + 0.4.9 + + + (2017-05-01) + + Release on GitHub + + +

+ +
    +
  • Feature: Forward compatibility with upcoming Socket v1.0 and v0.8
    +(#61 by @clue)
  • +
+ +
+ +

+ + + 0.4.8 + + + (2017-04-16) + + Release on GitHub + + +

+ +
    +
  • Feature: Add support for the AAAA record type to the protocol parser
    +(#58 by @othillo)
  • +
  • Feature: Add support for the PTR record type to the protocol parser
    +(#59 by @othillo)
  • +
+ +
+ +

+ + + 0.4.7 + + + (2017-03-31) + + Release on GitHub + + +

+ +
    +
  • Feature: Forward compatibility with upcoming Socket v0.6 and v0.7 component
    +(#57 by @clue)
  • +
+ +
+ +

+ + + 0.4.6 + + + (2017-03-11) + + Release on GitHub + + +

+ +
    +
  • Fix: Fix DNS timeout issues for Windows users and add forward compatibility
    +with Stream v0.5 and upcoming v0.6
    +(#53 by @clue)
  • +
  • Improve test suite by adding PHPUnit to require-dev
    +(#54 by @clue)
  • +
+ +
+ +

+ + + 0.4.5 + + + (2017-03-02) + + Release on GitHub + + +

+ +
    +
  • Fix: Ensure we ignore the case of the answer
    +(#51 by @WyriHaximus)
  • +
  • Feature: Add TimeoutExecutor and simplify internal APIs to allow internal
    +code re-use for upcoming versions.
    +(#48 and #49 by @clue)
  • +
+ +
+ +

+ + + 0.4.4 + + + (2017-02-13) + + Release on GitHub + + +

+ +
    +
  • Fix: Fix handling connection and stream errors
    +(#45 by @clue)
  • +
  • Feature: Add examples and forward compatibility with upcoming Socket v0.5 component
    +(#46 and #47 by @clue)
  • +
+ +
+

+ + 2016 +

+ + +

+ + + 0.4.3 + + + (2016-08-01) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Allow for cache adapter injection (#38 by @WyriHaximus)

    +
    $factory = new React\Dns\Resolver\Factory();
    +
    +$cache = new MyCustomCacheInstance();
    +$resolver = $factory->createCached('8.8.8.8', $loop, $cache);
    +
  • +
  • +

    Feature: Support Promise cancellation (#35 by @clue)

    +
    $promise = $resolver->resolve('reactphp.org');
    +
    +$promise->cancel();
    +
  • +
+ +
+ +

+ + + 0.4.2 + + + (2016-02-24) + + Release on GitHub + + +

+ +
    +
  • Repository maintenance, split off from main repo, improve test suite and documentation
  • +
  • First class support for PHP7 and HHVM (#34 by @clue)
  • +
  • Adjust compatibility to 5.3 (#30 by @clue)
  • +
+ +
+

+ + 2014 +

+ + +

+ + + 0.4.1 + + + (2014-04-12) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Fixed PSR-4 autoload path ()
  • +
+ +
+ +

+ + + 0.4.0 + + + (2014-02-02) + + Release on GitHub + + +

+ +
    +
  • BC break: Bump minimum PHP version to PHP 5.4, remove 5.3 specific hacks
  • +
  • BC break: Update to React/Promise 2.0
  • +
  • Bug fix: Properly resolve CNAME aliases
  • +
  • Dependency: Autoloading and filesystem structure now PSR-4 instead of PSR-0
  • +
  • Bump React dependencies to v0.4
  • +
+ +
+

+ + 2013 +

+ + +

+ + + 0.3.2 + + + (2013-04-27) + + Release on GitHub + + +

+ +
    +
  • Feature: Support default port for IPv6 addresses (@clue)
  • +
+ +
+ +

+ + + 0.3.0 + + + (2013-01-20) + + Release on GitHub + + +

+ +
    +
  • Bump React dependencies to v0.3
  • +
+ +
+

+ + 2012 +

+ + +

+ + + 0.2.6 + + + (2012-12-26) + + Release on GitHub + + +

+ +
    +
  • Feature: New cache component, used by DNS
  • +
+ +
+ +

+ + + 0.2.5 + + + (2012-11-19) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + 0.2.4 + + + (2012-11-17) + + Release on GitHub + + +

+ +
    +
  • Feature: Change to promise-based API (@jsor)
  • +
+ +
+ +

+ + + 0.2.3 + + + (2012-10-24) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + 0.2.2 + + + (2012-10-24) + + Release on GitHub + + +

+ + + +
+ +

+ + + 0.2.1 + + + (2012-09-24) + + Release on GitHub + + +

+ +
    +
  • Minor adjustments to DNS parser
  • +
+ +
+ +

+ + + 0.2.0 + + + (2012-09-10) + + Release on GitHub + + +

+ +
    +
  • Feature: DNS resolver
  • +
+ +
+
+ +
+
+
+ + + + + + diff --git a/dns/index.html b/dns/index.html new file mode 100644 index 000000000..59a96af0b --- /dev/null +++ b/dns/index.html @@ -0,0 +1,643 @@ + + + + + + + + DNS: +Dns - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

DNS

+ + +

Build Status

+

Async DNS resolver for ReactPHP.

+

The main point of the DNS component is to provide async DNS resolution. +However, it is really a toolkit for working with DNS messages, and could +easily be used to create a DNS server.

+

Table of contents

+ +

+Basic usage

+

The most basic usage is to just create a resolver through the resolver +factory. All you need to give it is a nameserver, then you can start resolving +names, baby!

+
$loop = React\EventLoop\Factory::create();
+
+$config = React\Dns\Config\Config::loadSystemConfigBlocking();
+$server = $config->nameservers ? reset($config->nameservers) : '8.8.8.8';
+
+$factory = new React\Dns\Resolver\Factory();
+$dns = $factory->create($server, $loop);
+
+$dns->resolve('igor.io')->then(function ($ip) {
+    echo "Host: $ip\n";
+});
+
+$loop->run();
+

See also the first example.

+

The Config class can be used to load the system default config. This is an +operation that may access the filesystem and block. Ideally, this method should +thus be executed only once before the loop starts and not repeatedly while it is +running. +Note that this class may return an empty configuration if the system config +can not be loaded. As such, you'll likely want to apply a default nameserver +as above if none can be found.

+
+

Note that the factory loads the hosts file from the filesystem once when +creating the resolver instance. +Ideally, this method should thus be executed only once before the loop starts +and not repeatedly while it is running.

+
+

Pending DNS queries can be cancelled by cancelling its pending promise like so:

+
$promise = $resolver->resolve('reactphp.org');
+
+$promise->cancel();
+

But there's more.

+

+Caching

+

You can cache results by configuring the resolver to use a CachedExecutor:

+
$loop = React\EventLoop\Factory::create();
+
+$config = React\Dns\Config\Config::loadSystemConfigBlocking();
+$server = $config->nameservers ? reset($config->nameservers) : '8.8.8.8';
+
+$factory = new React\Dns\Resolver\Factory();
+$dns = $factory->createCached($server, $loop);
+
+$dns->resolve('igor.io')->then(function ($ip) {
+    echo "Host: $ip\n";
+});
+
+...
+
+$dns->resolve('igor.io')->then(function ($ip) {
+    echo "Host: $ip\n";
+});
+
+$loop->run();
+

If the first call returns before the second, only one query will be executed. +The second result will be served from an in memory cache. +This is particularly useful for long running scripts where the same hostnames +have to be looked up multiple times.

+

See also the third example.

+

+Custom cache adapter

+

By default, the above will use an in memory cache.

+

You can also specify a custom cache implementing CacheInterface to handle the record cache instead:

+
$cache = new React\Cache\ArrayCache();
+$loop = React\EventLoop\Factory::create();
+$factory = new React\Dns\Resolver\Factory();
+$dns = $factory->createCached('8.8.8.8', $loop, $cache);
+

See also the wiki for possible cache implementations.

+

+Advanced Usage

+

For more advanced usages one can utilize the React\Dns\Query\Executor directly. +The following example looks up the IPv6 address for igor.io.

+
$loop = Factory::create();
+
+$executor = new Executor($loop, new Parser(), new BinaryDumper(), null);
+
+$executor->query(
+    '8.8.8.8:53', 
+    new Query($name, Message::TYPE_AAAA, Message::CLASS_IN, time())
+)->done(function (Message $message) {
+    foreach ($message->answers as $answer) {
+        echo 'IPv6: ' . $answer->data . PHP_EOL;
+    }
+}, 'printf');
+
+$loop->run();
+
+

See also the fourth example.

+

+HostsFileExecutor

+

Note that the above Executor class always performs an actual DNS query. +If you also want to take entries from your hosts file into account, you may +use this code:

+
$hosts = \React\Dns\Config\HostsFile::loadFromPathBlocking();
+
+$executor = new Executor($loop, new Parser(), new BinaryDumper(), null);
+$executor = new HostsFileExecutor($hosts, $executor);
+
+$executor->query(
+    '8.8.8.8:53', 
+    new Query('localhost', Message::TYPE_A, Message::CLASS_IN, time())
+);
+

+Install

+

The recommended way to install this library is through Composer. +New to Composer?

+

This will install the latest supported version:

+
$ composer require react/dns:^0.4.13
+

See also the CHANGELOG for details about version upgrades.

+

This project aims to run on any platform and thus does not require any PHP +extensions and supports running on legacy PHP 5.3 through current PHP 7+ and +HHVM. +It's highly recommended to use PHP 7+ for this project.

+

+Tests

+

To run the test suite, you first need to clone this repo and then install all +dependencies through Composer:

+
$ composer install
+

To run the test suite, go to the project root and run:

+
$ php vendor/bin/phpunit
+

The test suite also contains a number of functional integration tests that rely +on a stable internet connection. +If you do not want to run these, they can simply be skipped like this:

+
$ php vendor/bin/phpunit --exclude-group internet
+

+License

+

MIT, see LICENSE file.

+

+References

+
    +
  • +RFC 1034 Domain Names - Concepts and Facilities
  • +
  • +RFC 1035 Domain Names - Implementation and Specification
  • +
+
+ +
+
+
+ + + + + + diff --git a/dns/license.html b/dns/license.html new file mode 100644 index 000000000..d21fbeba9 --- /dev/null +++ b/dns/license.html @@ -0,0 +1,492 @@ + + + + + + + + DNS: License - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

DNS License

+ +

Copyright (c) 2012 Igor Wiedler, Chris Boden

+

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions:

+

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.

+
+ +
+
+
+ + + + + + diff --git a/event-loop/changelog.html b/event-loop/changelog.html new file mode 100644 index 000000000..2da4010dd --- /dev/null +++ b/event-loop/changelog.html @@ -0,0 +1,1128 @@ + + + + + + + + EventLoop: Changelog - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

EventLoop Changelog

+ + + +

+ + 2018 +

+ + +

+ + + 0.5.2 + + + (2018-04-24) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Improve memory consumption and runtime performance for StreamSelectLoop timers.
    +(#164 by @clue)

    +
  • +
  • +

    Improve test suite by removing I/O dependency at StreamSelectLoopTest to fix Mac OS X tests.
    +(#161 by @nawarian)

    +
  • +
+ +
+ +

+ + + 0.5.1 + + + (2018-04-09) + + Release on GitHub + + +

+ + + +
+ +

+ + + 0.5.0 + + + (2018-04-05) + + Release on GitHub + + +

+ +

A major feature release with a significant documentation overhaul and long overdue API cleanup!

+

This update involves a number of BC breaks due to dropped support for deprecated
+functionality. We've tried hard to avoid BC breaks where possible and minimize
+impact otherwise. We expect that most consumers of this package will actually
+not be affected by any BC breaks, see below for more details.

+

We realize that the changes listed below may seem overwhelming, but we've tried
+to be very clear about any possible BC breaks. Don't worry: In fact, all ReactPHP
+components are already compatible and support both this new release as well as
+providing backwards compatibility with the last release.

+
    +
  • +

    Feature / BC break: Add support for signal handling via new
    +LoopInterface::addSignal() and LoopInterface::removeSignal() methods.
    +(#104 by @WyriHaximus and #111 and #150 by @clue)

    +
    $loop->addSignal(SIGINT, function () {
    +    echo 'CTRL-C';
    +});
    +
  • +
  • +

    Feature: Significant documentation updates for LoopInterface and Factory.
    +(#100, #119, #126, #127, #159 and #160 by @clue, #113 by @WyriHaximus and #81 and #91 by @jsor)

    +
  • +
  • +

    Feature: Add examples to ease getting started
    +(#99, #100 and #125 by @clue, #59 by @WyriHaximus and #143 by @jsor)

    +
  • +
  • +

    Feature: Documentation for advanced timer concepts, such as monotonic time source vs wall-clock time
    +and high precision timers with millisecond accuracy or below.
    +(#130 and #157 by @clue)

    +
  • +
  • +

    Feature: Documentation for advanced stream concepts, such as edge-triggered event listeners
    +and stream buffers and allow throwing Exception if stream resource is not supported.
    +(#129 and #158 by @clue)

    +
  • +
  • +

    Feature: Throw BadMethodCallException on manual loop creation when required extension isn't installed.
    +(#153 by @WyriHaximus)

    +
  • +
  • +

    Feature / BC break: First class support for legacy PHP 5.3 through PHP 7.2 and HHVM
    +and remove all callable type hints for consistency reasons.
    +(#141 and #151 by @clue)

    +
  • +
  • +

    BC break: Documentation for timer API and clean up unneeded timer API.
    +(#102 by @clue)

    +

    Remove TimerInterface::cancel(), use LoopInterface::cancelTimer() instead:

    +
    // old (method invoked on timer instance)
    +$timer->cancel();
    +
    +// already supported before: invoke method on loop instance
    +$loop->cancelTimer($timer);
    +

    Remove unneeded TimerInterface::setData() and TimerInterface::getData(),
    +use closure binding to add arbitrary data to timer instead:

    +
    // old (limited setData() and getData() only allows single variable)
    +$name = 'Tester';
    +$timer = $loop->addTimer(1.0, function ($timer) {
    +    echo 'Hello ' . $timer->getData() . PHP_EOL;
    +});
    +$timer->setData($name);
    +
    +// already supported before: closure binding allows any number of variables
    +$name = 'Tester';
    +$loop->addTimer(1.0, function () use ($name) {
    +    echo 'Hello ' . $name . PHP_EOL;
    +});
    +

    Remove unneeded TimerInterface::getLoop(), use closure binding instead:

    +
    // old (getLoop() called on timer instance)
    +$loop->addTimer(0.1, function ($timer) {
    +    $timer->getLoop()->stop();
    +});
    +
    +// already supported before: use closure binding as usual
    +$loop->addTimer(0.1, function () use ($loop) {
    +    $loop->stop();
    +});
    +
  • +
  • +

    BC break: Remove unneeded LoopInterface::isTimerActive() and
    +TimerInterface::isActive() to reduce API surface.
    +(#133 by @clue)

    +
    // old (method on timer instance or on loop instance)
    +$timer->isActive();
    +$loop->isTimerActive($timer);
    +
  • +
  • +

    BC break: Move TimerInterface one level up to React\EventLoop\TimerInterface.
    +(#138 by @WyriHaximus)

    +
    // old (notice obsolete "Timer" namespace)
    +assert($timer instanceof React\EventLoop\Timer\TimerInterface);
    +
    +// new
    +assert($timer instanceof React\EventLoop\TimerInterface);
    +
  • +
  • +

    BC break: Remove unneeded LoopInterface::nextTick() (and internal NextTickQueue),
    +use LoopInterface::futureTick() instead.
    +(#30 by @clue)

    +
    // old (removed)
    +$loop->nextTick(function () {
    +    echo 'tick';
    +});
    +
    +// already supported before
    +$loop->futureTick(function () {
    +    echo 'tick';
    +});
    +
  • +
  • +

    BC break: Remove unneeded $loop argument for LoopInterface::futureTick()
    +(and fix internal cyclic dependency).
    +(#103 by @clue)

    +
    // old ($loop gets passed by default)
    +$loop->futureTick(function ($loop) {
    +    $loop->stop();
    +});
    +
    +// already supported before: use closure binding as usual
    +$loop->futureTick(function () use ($loop) {
    +    $loop->stop();
    +});
    +
  • +
  • +

    BC break: Remove unneeded LoopInterface::tick().
    +(#72 by @jsor)

    +
    // old (removed)
    +$loop->tick();
    +
    +// suggested work around for testing purposes only
    +$loop->futureTick(function () use ($loop) {
    +    $loop->stop();
    +});
    +
  • +
  • +

    BC break: Documentation for advanced stream API and clean up unneeded stream API.
    +(#110 by @clue)

    +

    Remove unneeded $loop argument for LoopInterface::addReadStream()
    +and LoopInterface::addWriteStream(), use closure binding instead:

    +
    // old ($loop gets passed by default)
    +$loop->addReadStream($stream, function ($stream, $loop) {
    +    $loop->removeReadStream($stream);
    +});
    +
    +// already supported before: use closure binding as usual
    +$loop->addReadStream($stream, function ($stream) use ($loop) {
    +    $loop->removeReadStream($stream);
    +});
    +
  • +
  • +

    BC break: Remove unneeded LoopInterface::removeStream() method,
    +use LoopInterface::removeReadStream() and LoopInterface::removeWriteStream() instead.
    +(#118 by @clue)

    +
    // old
    +$loop->removeStream($stream);
    +
    +// already supported before
    +$loop->removeReadStream($stream);
    +$loop->removeWriteStream($stream);
    +
  • +
  • +

    BC break: Rename LibEventLoop to ExtLibeventLoop and LibEvLoop to ExtLibevLoop
    +for consistent naming for event loop implementations.
    +(#128 by @clue)

    +
  • +
  • +

    BC break: Remove optional EventBaseConfig argument from ExtEventLoop
    +and make its FEATURE_FDS enabled by default.
    +(#156 by @WyriHaximus)

    +
  • +
  • +

    BC break: Mark all classes as final to discourage inheritance.
    +(#131 by @clue)

    +
  • +
  • +

    Fix: Fix ExtEventLoop to keep track of stream resources (refcount)
    +(#123 by @clue)

    +
  • +
  • +

    Fix: Ensure large timer interval does not overflow on 32bit systems
    +(#132 by @clue)

    +
  • +
  • +

    Fix: Fix separately removing readable and writable side of stream when closing
    +(#139 by @clue)

    +
  • +
  • +

    Fix: Properly clean up event watchers for ext-event and ext-libev
    +(#149 by @clue)

    +
  • +
  • +

    Fix: Minor code cleanup and remove unneeded references
    +(#145 by @seregazhuk)

    +
  • +
  • +

    Fix: Discourage outdated ext-libevent on PHP 7
    +(#62 by @cboden)

    +
  • +
  • +

    Improve test suite by adding forward compatibility with PHPUnit 6 and PHPUnit 5,
    +lock Travis distro so new defaults will not break the build,
    +improve test suite to be less fragile and increase test timeouts,
    +test against PHP 7.2 and reduce fwrite() call length to one chunk.
    +(#106 and #144 by @clue, #120 and #124 by @carusogabriel, #147 by nawarian and #92 by @kelunik)

    +
  • +
  • +

    A number of changes were originally planned for this release but have been backported
    +to the last v0.4.3 already: #74, #76, #79, #81 (refs #65, #66, #67), #88 and #93

    +
  • +
+ +
+

+ + 2017 +

+ + +

+ + + 0.4.3 + + + (2017-04-27) + + Release on GitHub + + +

+ +

This is a bug fix and improvement release:

+
    +
  • Bug fix: Bugfix in the usage sample code #57 (@dandelionred)
  • +
  • Improvement: Remove branch-alias definition #53 (@WyriHaximus)
  • +
  • Improvement: StreamSelectLoop: Use fresh time so Timers added during stream events are accurate #51 (@andrewminerd)
  • +
  • Improvement: Avoid deprecation warnings in test suite due to deprecation of getMock() in PHPUnit #68 (@martinschroeder)
  • +
  • Improvement: Add PHPUnit 4.8 to require-dev #69 (@shaunbramley)
  • +
  • Improvement: Increase test timeouts for HHVM and unify timeout handling #70 (@clue)
  • +
  • Improvement: Travis improvements (backported from #74) #75 (@clue)
  • +
  • Improvement: Test suite now uses socket pairs instead of memory streams #66 (@martinschroeder)
  • +
  • Improvement: StreamSelectLoop: Test suite uses signal constant names in data provider #67 (@martinschroeder)
  • +
  • Improvement: ExtEventLoop: No longer suppress all errors #65 (@mamciek)
  • +
  • Improvement: Readme cleanup #89 (@jsor)
  • +
  • Improvement: Restructure and improve README #90 (@jsor)
  • +
  • Bug fix: StreamSelectLoop: Fix erroneous zero-time sleep (backport to 0.4) #94 (@jsor)
  • +
+ +
+

+ + 2016 +

+ + +

+ + + 0.3.5 + + + (2016-12-28) + + Release on GitHub + + +

+ +

This is a compatibility release that eases upgrading to the v0.4 release branch.
+You should consider upgrading to the v0.4 release branch.

+
    +
  • Feature: Cap min timer interval at 1µs, thus improving compatibility with v0.4
    +(#47 by @clue)
  • +
+ +
+ +

+ + + 0.4.2 + + + (2016-03-08) + + Release on GitHub + + +

+ +
    +
  • Bug fix: No longer error when signals sent to StreamSelectLoop
  • +
  • Support HHVM and PHP7 (@ondrejmirtes, @cebe)
  • +
  • Feature: Added support for EventConfig for ExtEventLoop (@steverhoades)
  • +
  • Bug fix: Fixed an issue loading loop extension libs via autoloader (@czarpino)
  • +
+ +
+

+ + 2014 +

+ + +

+ + + 0.4.1 + + + (2014-02-26) + + Release on GitHub + + +

+ +
    +
  • Bug fix: null timeout in StreamSelectLoop causing 100% CPU usage (@clue)
  • +
  • Bug fix: v0.3.4 changes merged for v0.4.1
  • +
+ +
+ +

+ + + 0.4.0 + + + (2014-02-02) + + Release on GitHub + + +

+ +
    +
  • Feature: Added EventLoopInterface::nextTick(), implemented in all event loops (@jmalloc)
  • +
  • Feature: Added EventLoopInterface::futureTick(), implemented in all event loops (@jmalloc)
  • +
  • Feature: Added ExtEventLoop implementation using pecl/event (@jmalloc)
  • +
  • BC break: Bump minimum PHP version to PHP 5.4, remove 5.3 specific hacks
  • +
  • BC break: New method: EventLoopInterface::nextTick()
  • +
  • BC break: New method: EventLoopInterface::futureTick()
  • +
  • Dependency: Autoloading and filesystem structure now PSR-4 instead of PSR-0
  • +
+ +
+

+ + 2013 +

+ + +

+ + + 0.3.4 + + + (2013-07-21) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Changed StreamSelectLoop to use non-blocking behavior on tick() (@astephens25)
  • +
+ +
+ +

+ + + 0.3.3 + + + (2013-07-08) + + Release on GitHub + + +

+ +
    +
  • Bug fix: No error on removing non-existent streams (@clue)
  • +
  • Bug fix: Do not silently remove feof listeners in LibEvLoop
  • +
+ +
+ +

+ + + 0.3.0 + + + (2013-01-14) + + Release on GitHub + + +

+ +
    +
  • BC break: New timers API (@nrk)
  • +
  • BC break: Remove check on return value from stream callbacks (@nrk)
  • +
+ +
+ +

+ + + 0.2.7 + + + (2013-01-05) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Fix libevent timers with PHP 5.3
  • +
  • Bug fix: Fix libevent timer cancellation (@nrk)
  • +
+ +
+

+ + 2012 +

+ + +

+ + + 0.2.6 + + + (2012-12-26) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Plug memory issue in libevent timers (@cameronjacobson)
  • +
  • Bug fix: Correctly pause LibEvLoop on stop()
  • +
+ +
+ +

+ + + 0.2.3 + + + (2012-11-12) + + Release on GitHub + + +

+ +
    +
  • Feature: LibEvLoop, integration of php-libev
  • +
+ +
+ +

+ + + 0.2.0 + + + (2012-09-10) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + 0.1.1 + + + (2012-07-12) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + 0.1.0 + + + (2012-07-11) + + Release on GitHub + + +

+ +
    +
  • First tagged release
  • +
+ +
+
+ +
+
+
+ + + + + + diff --git a/event-loop/index.html b/event-loop/index.html new file mode 100644 index 000000000..57d050fac --- /dev/null +++ b/event-loop/index.html @@ -0,0 +1,1080 @@ + + + + + + + + EventLoop: +EventLoop Component - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

EventLoop

+ + +

Build Status

+

ReactPHP's core reactor event loop that libraries can use for evented I/O.

+

In order for async based libraries to be interoperable, they need to use the +same event loop. This component provides a common LoopInterface that any +library can target. This allows them to be used in the same loop, with one +single run() call that is controlled by the user.

+

Table of Contents

+ +

+Quickstart example

+

Here is an async HTTP server built with just the event loop.

+
$loop = React\EventLoop\Factory::create();
+
+$server = stream_socket_server('tcp://127.0.0.1:8080');
+stream_set_blocking($server, false);
+
+$loop->addReadStream($server, function ($server) use ($loop) {
+    $conn = stream_socket_accept($server);
+    $data = "HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nHi\n";
+    $loop->addWriteStream($conn, function ($conn) use (&$data, $loop) {
+        $written = fwrite($conn, $data);
+        if ($written === strlen($data)) {
+            fclose($conn);
+            $loop->removeWriteStream($conn);
+        } else {
+            $data = substr($data, $written);
+        }
+    });
+});
+
+$loop->addPeriodicTimer(5, function () {
+    $memory = memory_get_usage() / 1024;
+    $formatted = number_format($memory, 3).'K';
+    echo "Current memory usage: {$formatted}\n";
+});
+
+$loop->run();
+

See also the examples.

+

+Usage

+

Typical applications use a single event loop which is created at the beginning +and run at the end of the program.

+
// [1]
+$loop = React\EventLoop\Factory::create();
+
+// [2]
+$loop->addPeriodicTimer(1, function () {
+    echo "Tick\n";
+});
+
+$stream = new React\Stream\ReadableResourceStream(
+    fopen('file.txt', 'r'),
+    $loop
+);
+
+// [3]
+$loop->run();
+
    +
  1. The loop instance is created at the beginning of the program. A convenience +factory React\EventLoop\Factory::create() is provided by this library which +picks the best available loop implementation.
  2. +
  3. The loop instance is used directly or passed to library and application code. +In this example, a periodic timer is registered with the event loop which +simply outputs Tick every second and a +readable stream +is created by using ReactPHP's +stream component for demonstration +purposes.
  4. +
  5. The loop is run with a single $loop->run() call at the end of the program.
  6. +
+

+Factory

+

The Factory class exists as a convenient way to pick the best available +event loop implementation.

+

+create()

+

The create(): LoopInterface method can be used to create a new event loop +instance:

+
$loop = React\EventLoop\Factory::create();
+

This method always returns an instance implementing LoopInterface, +the actual event loop implementation is an implementation detail.

+

This method should usually only be called once at the beginning of the program.

+

+Loop implementations

+

In addition to the LoopInterface, there are a number of +event loop implementations provided.

+

All of the event loops support these features:

+
    +
  • File descriptor polling
  • +
  • One-off timers
  • +
  • Periodic timers
  • +
  • Deferred execution on future loop tick
  • +
+

For most consumers of this package, the underlying event loop implementation is +an implementation detail. +You should use the Factory to automatically create a new instance.

+

Advanced! If you explicitly need a certain event loop implementation, you can +manually instantiate one of the following classes. +Note that you may have to install the required PHP extensions for the respective +event loop implementation first or they will throw a BadMethodCallException on creation.

+

+StreamSelectLoop

+

A stream_select() based event loop.

+

This uses the stream_select() +function and is the only implementation which works out of the box with PHP.

+

This event loop works out of the box on PHP 5.3 through PHP 7+ and HHVM. +This means that no installation is required and this library works on all +platforms and supported PHP versions. +Accordingly, the Factory will use this event loop by default if +you do not install any of the event loop extensions listed below.

+

Under the hood, it does a simple select system call. +This system call is limited to the maximum file descriptor number of +FD_SETSIZE (platform dependent, commonly 1024) and scales with O(m) +(m being the maximum file descriptor number passed). +This means that you may run into issues when handling thousands of streams +concurrently and you may want to look into using one of the alternative +event loop implementations listed below in this case. +If your use case is among the many common use cases that involve handling only +dozens or a few hundred streams at once, then this event loop implementation +performs really well.

+

If you want to use signal handling (see also addSignal() below), +this event loop implementation requires ext-pcntl. +This extension is only available for Unix-like platforms and does not support +Windows. +It is commonly installed as part of many PHP distributions. +If this extension is missing (or you're running on Windows), signal handling is +not supported and throws a BadMethodCallException instead.

+

This event loop is known to rely on wall-clock time to schedule future +timers, because a monotonic time source is not available in PHP by default. +While this does not affect many common use cases, this is an important +distinction for programs that rely on a high time precision or on systems +that are subject to discontinuous time adjustments (time jumps). +This means that if you schedule a timer to trigger in 30s and then adjust +your system time forward by 20s, the timer may trigger in 10s. +See also addTimer() for more details.

+

+ExtEventLoop

+

An ext-event based event loop.

+

This uses the event PECL extension. +It supports the same backends as libevent.

+

This loop is known to work with PHP 5.4 through PHP 7+.

+

+ExtEvLoop

+

An ext-ev based event loop.

+

This loop uses the ev PECL extension, that +provides an interface to libev library.

+

This loop is known to work with PHP 5.4 through PHP 7+.

+

+ExtLibeventLoop

+

An ext-libevent based event loop.

+

This uses the libevent PECL extension. +libevent itself supports a number of system-specific backends (epoll, kqueue).

+

This event loop does only work with PHP 5. +An unofficial update for +PHP 7 does exist, but it is known to cause regular crashes due to SEGFAULTs. +To reiterate: Using this event loop on PHP 7 is not recommended. +Accordingly, the Factory will not try to use this event loop on +PHP 7.

+

This event loop is known to trigger a readable listener only if +the stream becomes readable (edge-triggered) and may not trigger if the +stream has already been readable from the beginning. +This also implies that a stream may not be recognized as readable when data +is still left in PHP's internal stream buffers. +As such, it's recommended to use stream_set_read_buffer($stream, 0); +to disable PHP's internal read buffer in this case. +See also addReadStream() for more details.

+

+ExtLibevLoop

+

An ext-libev based event loop.

+

This uses an unofficial libev extension. +It supports the same backends as libevent.

+

This loop does only work with PHP 5. +An update for PHP 7 is unlikely +to happen any time soon.

+

+LoopInterface

+

+run()

+

The run(): void method can be used to +run the event loop until there are no more tasks to perform.

+

For many applications, this method is the only directly visible +invocation on the event loop. +As a rule of thumb, it is usally recommended to attach everything to the +same loop instance and then run the loop once at the bottom end of the +application.

+
$loop->run();
+

This method will keep the loop running until there are no more tasks +to perform. In other words: This method will block until the last +timer, stream and/or signal has been removed.

+

Likewise, it is imperative to ensure the application actually invokes +this method once. Adding listeners to the loop and missing to actually +run it will result in the application exiting without actually waiting +for any of the attached listeners.

+

This method MUST NOT be called while the loop is already running. +This method MAY be called more than once after it has explicity been +stop()ped or after it automatically stopped because it +previously did no longer have anything to do.

+

+stop()

+

The stop(): void method can be used to +instruct a running event loop to stop.

+

This method is considered advanced usage and should be used with care. +As a rule of thumb, it is usually recommended to let the loop stop +only automatically when it no longer has anything to do.

+

This method can be used to explicitly instruct the event loop to stop:

+
$loop->addTimer(3.0, function () use ($loop) {
+    $loop->stop();
+});
+

Calling this method on a loop instance that is not currently running or +on a loop instance that has already been stopped has no effect.

+

+addTimer()

+

The addTimer(float $interval, callable $callback): TimerInterface method can be used to +enqueue a callback to be invoked once after the given interval.

+

The timer callback function MUST be able to accept a single parameter, +the timer instance as also returned by this method or you MAY use a +function which has no parameters at all.

+

The timer callback function MUST NOT throw an Exception. +The return value of the timer callback function will be ignored and has +no effect, so for performance reasons you're recommended to not return +any excessive data structures.

+

Unlike addPeriodicTimer(), this method will ensure +the callback will be invoked only once after the given interval. +You can invoke cancelTimer to cancel a pending timer.

+
$loop->addTimer(0.8, function () {
+    echo 'world!' . PHP_EOL;
+});
+
+$loop->addTimer(0.3, function () {
+    echo 'hello ';
+});
+

See also example #1.

+

If you want to access any variables within your callback function, you +can bind arbitrary data to a callback closure like this:

+
function hello($name, LoopInterface $loop)
+{
+    $loop->addTimer(1.0, function () use ($name) {
+        echo "hello $name\n";
+    });
+}
+
+hello('Tester', $loop);
+

This interface does not enforce any particular timer resolution, so +special care may have to be taken if you rely on very high precision with +millisecond accuracy or below. Event loop implementations SHOULD work on +a best effort basis and SHOULD provide at least millisecond accuracy +unless otherwise noted. Many existing event loop implementations are +known to provide microsecond accuracy, but it's generally not recommended +to rely on this high precision.

+

Similarly, the execution order of timers scheduled to execute at the +same time (within its possible accuracy) is not guaranteed.

+

This interface suggests that event loop implementations SHOULD use a +monotonic time source if available. Given that a monotonic time source is +not available on PHP by default, event loop implementations MAY fall back +to using wall-clock time. +While this does not affect many common use cases, this is an important +distinction for programs that rely on a high time precision or on systems +that are subject to discontinuous time adjustments (time jumps). +This means that if you schedule a timer to trigger in 30s and then adjust +your system time forward by 20s, the timer SHOULD still trigger in 30s. +See also event loop implementations for more details.

+

+addPeriodicTimer()

+

The addPeriodicTimer(float $interval, callable $callback): TimerInterface method can be used to +enqueue a callback to be invoked repeatedly after the given interval.

+

The timer callback function MUST be able to accept a single parameter, +the timer instance as also returned by this method or you MAY use a +function which has no parameters at all.

+

The timer callback function MUST NOT throw an Exception. +The return value of the timer callback function will be ignored and has +no effect, so for performance reasons you're recommended to not return +any excessive data structures.

+

Unlike addTimer(), this method will ensure the the +callback will be invoked infinitely after the given interval or until you +invoke cancelTimer.

+
$timer = $loop->addPeriodicTimer(0.1, function () {
+    echo 'tick!' . PHP_EOL;
+});
+
+$loop->addTimer(1.0, function () use ($loop, $timer) {
+    $loop->cancelTimer($timer);
+    echo 'Done' . PHP_EOL;
+});
+

See also example #2.

+

If you want to limit the number of executions, you can bind +arbitrary data to a callback closure like this:

+
function hello($name, LoopInterface $loop)
+{
+    $n = 3;
+    $loop->addPeriodicTimer(1.0, function ($timer) use ($name, $loop, &$n) {
+        if ($n > 0) {
+            --$n;
+            echo "hello $name\n";
+        } else {
+            $loop->cancelTimer($timer);
+        }
+    });
+}
+
+hello('Tester', $loop);
+

This interface does not enforce any particular timer resolution, so +special care may have to be taken if you rely on very high precision with +millisecond accuracy or below. Event loop implementations SHOULD work on +a best effort basis and SHOULD provide at least millisecond accuracy +unless otherwise noted. Many existing event loop implementations are +known to provide microsecond accuracy, but it's generally not recommended +to rely on this high precision.

+

Similarly, the execution order of timers scheduled to execute at the +same time (within its possible accuracy) is not guaranteed.

+

This interface suggests that event loop implementations SHOULD use a +monotonic time source if available. Given that a monotonic time source is +not available on PHP by default, event loop implementations MAY fall back +to using wall-clock time. +While this does not affect many common use cases, this is an important +distinction for programs that rely on a high time precision or on systems +that are subject to discontinuous time adjustments (time jumps). +This means that if you schedule a timer to trigger in 30s and then adjust +your system time forward by 20s, the timer SHOULD still trigger in 30s. +See also event loop implementations for more details.

+

Additionally, periodic timers may be subject to timer drift due to +re-scheduling after each invocation. As such, it's generally not +recommended to rely on this for high precision intervals with millisecond +accuracy or below.

+

+cancelTimer()

+

The cancelTimer(TimerInterface $timer): void method can be used to +cancel a pending timer.

+

See also addPeriodicTimer() and example #2.

+

Calling this method on a timer instance that has not been added to this +loop instance or on a timer that has already been cancelled has no effect.

+

+futureTick()

+

The futureTick(callable $listener): void method can be used to +schedule a callback to be invoked on a future tick of the event loop.

+

This works very much similar to timers with an interval of zero seconds, +but does not require the overhead of scheduling a timer queue.

+

The tick callback function MUST be able to accept zero parameters.

+

The tick callback function MUST NOT throw an Exception. +The return value of the tick callback function will be ignored and has +no effect, so for performance reasons you're recommended to not return +any excessive data structures.

+

If you want to access any variables within your callback function, you +can bind arbitrary data to a callback closure like this:

+
function hello($name, LoopInterface $loop)
+{
+    $loop->futureTick(function () use ($name) {
+        echo "hello $name\n";
+    });
+}
+
+hello('Tester', $loop);
+

Unlike timers, tick callbacks are guaranteed to be executed in the order +they are enqueued. +Also, once a callback is enqueued, there's no way to cancel this operation.

+

This is often used to break down bigger tasks into smaller steps (a form +of cooperative multitasking).

+
$loop->futureTick(function () {
+    echo 'b';
+});
+$loop->futureTick(function () {
+    echo 'c';
+});
+echo 'a';
+

See also example #3.

+

+addSignal()

+

The addSignal(int $signal, callable $listener): void method can be used to +register a listener to be notified when a signal has been caught by this process.

+

This is useful to catch user interrupt signals or shutdown signals from +tools like supervisor or systemd.

+

The listener callback function MUST be able to accept a single parameter, +the signal added by this method or you MAY use a function which +has no parameters at all.

+

The listener callback function MUST NOT throw an Exception. +The return value of the listener callback function will be ignored and has +no effect, so for performance reasons you're recommended to not return +any excessive data structures.

+
$loop->addSignal(SIGINT, function (int $signal) {
+    echo 'Caught user interrupt signal' . PHP_EOL;
+});
+

See also example #4.

+

Signaling is only available on Unix-like platform, Windows isn't +supported due to operating system limitations. +This method may throw a BadMethodCallException if signals aren't +supported on this platform, for example when required extensions are +missing.

+

Note: A listener can only be added once to the same signal, any +attempts to add it more then once will be ignored.

+

+removeSignal()

+

The removeSignal(int $signal, callable $listener): void method can be used to +remove a previously added signal listener.

+
$loop->removeSignal(SIGINT, $listener);
+

Any attempts to remove listeners that aren't registered will be ignored.

+

+addReadStream()

+
+

Advanced! Note that this low-level API is considered advanced usage. +Most use cases should probably use the higher-level +readable Stream API +instead.

+
+

The addReadStream(resource $stream, callable $callback): void method can be used to +register a listener to be notified when a stream is ready to read.

+

The first parameter MUST be a valid stream resource that supports +checking whether it is ready to read by this loop implementation. +A single stream resource MUST NOT be added more than once. +Instead, either call removeReadStream() first or +react to this event with a single listener and then dispatch from this +listener. This method MAY throw an Exception if the given resource type +is not supported by this loop implementation.

+

The listener callback function MUST be able to accept a single parameter, +the stream resource added by this method or you MAY use a function which +has no parameters at all.

+

The listener callback function MUST NOT throw an Exception. +The return value of the listener callback function will be ignored and has +no effect, so for performance reasons you're recommended to not return +any excessive data structures.

+

If you want to access any variables within your callback function, you +can bind arbitrary data to a callback closure like this:

+
$loop->addReadStream($stream, function ($stream) use ($name) {
+    echo $name . ' said: ' . fread($stream);
+});
+

See also example #11.

+

You can invoke removeReadStream() to remove the +read event listener for this stream.

+

The execution order of listeners when multiple streams become ready at +the same time is not guaranteed.

+

Some event loop implementations are known to only trigger the listener if +the stream becomes readable (edge-triggered) and may not trigger if the +stream has already been readable from the beginning. +This also implies that a stream may not be recognized as readable when data +is still left in PHP's internal stream buffers. +As such, it's recommended to use stream_set_read_buffer($stream, 0); +to disable PHP's internal read buffer in this case.

+

+addWriteStream()

+
+

Advanced! Note that this low-level API is considered advanced usage. +Most use cases should probably use the higher-level +writable Stream API +instead.

+
+

The addWriteStream(resource $stream, callable $callback): void method can be used to +register a listener to be notified when a stream is ready to write.

+

The first parameter MUST be a valid stream resource that supports +checking whether it is ready to write by this loop implementation. +A single stream resource MUST NOT be added more than once. +Instead, either call removeWriteStream() first or +react to this event with a single listener and then dispatch from this +listener. This method MAY throw an Exception if the given resource type +is not supported by this loop implementation.

+

The listener callback function MUST be able to accept a single parameter, +the stream resource added by this method or you MAY use a function which +has no parameters at all.

+

The listener callback function MUST NOT throw an Exception. +The return value of the listener callback function will be ignored and has +no effect, so for performance reasons you're recommended to not return +any excessive data structures.

+

If you want to access any variables within your callback function, you +can bind arbitrary data to a callback closure like this:

+
$loop->addWriteStream($stream, function ($stream) use ($name) {
+    fwrite($stream, 'Hello ' . $name);
+});
+

See also example #12.

+

You can invoke removeWriteStream() to remove the +write event listener for this stream.

+

The execution order of listeners when multiple streams become ready at +the same time is not guaranteed.

+

+removeReadStream()

+

The removeReadStream(resource $stream): void method can be used to +remove the read event listener for the given stream.

+

Removing a stream from the loop that has already been removed or trying +to remove a stream that was never added or is invalid has no effect.

+

+removeWriteStream()

+

The removeWriteStream(resource $stream): void method can be used to +remove the write event listener for the given stream.

+

Removing a stream from the loop that has already been removed or trying +to remove a stream that was never added or is invalid has no effect.

+

+Install

+

The recommended way to install this library is through Composer. +New to Composer?

+

This will install the latest supported version:

+
$ composer require react/event-loop:^0.5.2
+

See also the CHANGELOG for details about version upgrades.

+

This project aims to run on any platform and thus does not require any PHP +extensions and supports running on legacy PHP 5.3 through current PHP 7+ and +HHVM. +It's highly recommended to use PHP 7+ for this project.

+

Installing any of the event loop extensions is suggested, but entirely optional. +See also event loop implementations for more details.

+

+Tests

+

To run the test suite, you first need to clone this repo and then install all +dependencies through Composer:

+
$ composer install
+

To run the test suite, go to the project root and run:

+
$ php vendor/bin/phpunit
+

+License

+

MIT, see LICENSE file.

+

+More

+ +
+ +
+
+
+ + + + + + diff --git a/event-loop/license.html b/event-loop/license.html new file mode 100644 index 000000000..6296aa51a --- /dev/null +++ b/event-loop/license.html @@ -0,0 +1,537 @@ + + + + + + + + EventLoop: License - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

EventLoop License

+ +

Copyright (c) 2012 Igor Wiedler, Chris Boden

+

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions:

+

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.

+
+ +
+
+
+ + + + + + diff --git a/favicon-32x32.png b/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..14d1ec5a4c74bf4deeaee0c29f4738257b26f127 GIT binary patch literal 719 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 literal 0 HcmV?d00001 diff --git a/http-client/changelog.html b/http-client/changelog.html new file mode 100644 index 000000000..997c6ae15 --- /dev/null +++ b/http-client/changelog.html @@ -0,0 +1,1390 @@ + + + + + + + + HTTPClient: Changelog - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

HTTPClient Changelog

+ + + +

+ + 2018 +

+ + +

+ + + 0.5.9 + + + (2018-04-10) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Support legacy HTTP servers that use only LF instead of CRLF.
    +(#130 by @clue)

    +
  • +
  • +

    Improve test suite by applying maximum test timeouts for integration tests.
    +(#131 by @clue)

    +
  • +
+ +
+ +

+ + + 0.5.8 + + + (2018-02-09) + + Release on GitHub + + +

+ +
    +
  • +

    Support legacy PHP 5.3 through PHP 7.2 and HHVM
    +(#126 and #127 by @clue)

    +
  • +
  • +

    Improve backwards compatibility with Promise v1 and
    +use RingCentral to improve interoperability with react/http.
    +(#124 and #125 by @clue)

    +
  • +
+ +
+ +

+ + + 0.5.7 + + + (2018-02-08) + + Release on GitHub + + +

+ +
    +
  • +

    Fix: Ignore excessive whitespace in chunk header for Transfer-Encoding: chunked
    +(#123 by @DangerLifter and @clue)

    +
  • +
  • +

    Fix: Ignore invalid incoming Transfer-Encoding response header
    +(#122 by @clue)

    +
  • +
  • +

    Improve documentation for Client (and advanced Connector)
    +(#111 by @jsor and #121 by @clue)

    +
  • +
  • +

    Improve test suite by adding support for PHPUnit 6
    +(#112 by @carusogabriel)

    +
  • +
+ +
+

+ + 2017 +

+ + +

+ + + 0.5.6 + + + (2017-09-17) + + Release on GitHub + + +

+ +
    +
  • Feature: Update Socket component to support HTTP over Unix domain sockets (UDS)
    +(#110 by @clue)
  • +
+ +
+ +

+ + + 0.5.5 + + + (2017-09-10) + + Release on GitHub + + +

+ +
    +
  • Fix: Update Socket component to work around sending secure HTTPS requests with PHP < 7.1.4
    +(#109 by @clue)
  • +
+ +
+ +

+ + + 0.5.4 + + + (2017-08-25) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Update Socket dependency to support hosts file on all platforms
    +(#108 by @clue)

    +

    This means that HTTP requests to hosts such as localhost will now work as
    +expected across all platforms with no changes required:

    +
    $client = new Client($loop);
    +$request = $client->request('GET', 'http://localhost/');
    +$request->on('response', function (Response $response) {
    +    //
    +});
    +$request->end();
    +
  • +
+ +
+ +

+ + + 0.5.3 + + + (2017-08-16) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Target evenement 3.0 a long side 2.0
    +(#106 by @WyriHaximus)

    +
  • +
  • +

    Improve test suite by locking Travis distro so new defaults will not break the build
    +(#105 by @clue)

    +
  • +
+ +
+ +

+ + + 0.5.2 + + + (2017-06-27) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Support passing arrays for request header values
    +(#100 by @clue)

    +
  • +
  • +

    Fix: Fix merging default headers if overwritten with custom case headers
    +(#101 by @clue)

    +
  • +
+ +
+ +

+ + + 0.5.1 + + + (2017-06-18) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Emit error event if request URL is invalid
    +(#99 by @clue)

    +
  • +
  • +

    Feature: Support OPTIONS method with asterisk-form (OPTIONS * HTTP/1.1)
    +(#98 by @clue)

    +
  • +
  • +

    Improve documentation for event semantics
    +(#97 by @clue)

    +
  • +
+ +
+ +

+ + + 0.5.0 + + + (2017-05-22) + + Release on GitHub + + +

+ +
    +
  • +

    Feature / BC break: Replace Factory with simple Client constructor
    +(#85 by @clue)

    +

    The Client now accepts a required LoopInterface and an optional
    +ConnectorInterface. It will now create a default Connector if none
    +has been given.

    +
    // old
    +$dnsResolverFactory = new React\Dns\Resolver\Factory();
    +$dnsResolver = $dnsResolverFactory->createCached('8.8.8.8', $loop);
    +$factory = new React\HttpClient\Factory();
    +$client = $factory->create($loop, $dnsResolver);
    +
    +// new
    +$client = new React\HttpClient\Client($loop);
    +
  • +
  • +

    Feature: Request::close() now cancels pending connection attempt
    +(#91 by @clue)

    +
  • +
  • +

    Feature / BC break: Replace deprecated SocketClient with new Socket component
    +(#74, #84 and #88 by @clue)

    +
  • +
  • +

    Feature / BC break: Consistent stream semantics and forward compatibility with upcoming Stream v1.0
    +(#90 by @clue)

    +
  • +
  • +

    Feature: Forward compatibility with upcoming EventLoop v1.0 and v0.5
    +(#89 by @clue)

    +
  • +
  • +

    Fix: Catch Guzzle parser exception
    +(#82 by @djagya)

    +
  • +
+ +
+ +

+ + + 0.4.17 + + + (2017-03-20) + + Release on GitHub + + +

+ +
    +
  • Improvement: Add PHPUnit to require-dev #75 @jsor
  • +
  • Fix: Fix chunk header to be case-insensitive and allow leading zeros for end chunk #77 @mdrost
  • +
+ +
+ +

+ + + 0.4.16 + + + (2017-03-01) + + Release on GitHub + + +

+ + + +
+

+ + 2016 +

+ + +

+ + + 0.4.15 + + + (2016-12-02) + + Release on GitHub + + +

+ +
    +
  • Improvement: Add examples #69 @clue
  • +
  • Fix: Ensure checking for 0 length chunk, when we should check for it #71 @WyriHaximus
  • +
+ +
+ +

+ + + 0.4.14 + + + (2016-10-28) + + Release on GitHub + + +

+ +
    +
  • Fix: Ensure the first bit of body directly after the headers is emitted into the stream #68 @WyriHaximus
  • +
+ +
+ +

+ + + 0.4.13 + + + (2016-10-19) + + Release on GitHub + + +

+ +
    +
  • Fix: Ensure Request emits initial Response data as string #66 @mmelvin0
  • +
+ +
+ +

+ + + 0.4.12 + + + (2016-10-06) + + Release on GitHub + + +

+ +
    +
  • Fix: Changed $stream from DuplexStreamInterface to ReadableStreamInterface in Response constructor #63 @WyriHaximus
  • +
+ +
+ +

+ + + 0.4.11 + + + (2016-09-15) + + Release on GitHub + + +

+ + + +
+ +

+ + + 0.3.2 + + + (2016-03-24) + + Release on GitHub + + +

+ +
    +
  • Improvement: Broader guzzle/parser version req @cboden
  • +
  • Improvement: Improve forwards compatibility with all supported versions @clue
  • +
+ +
+ +

+ + + 0.4.10 + + + (2016-03-21) + + Release on GitHub + + +

+ +
    +
  • Improvement: Update react/socket-client dependency to all supported versions @clue
  • +
+ +
+ +

+ + + 0.4.9 + + + (2016-03-08) + + Release on GitHub + + +

+ +
    +
  • Improvement: PHP 7 memory leak, related to PHP bug 71737 @jmalloc
  • +
  • Improvement: Clean up all listeners when closing request @weichenlin
  • +
+ +
+

+ + 2015 +

+ + +

+ + + 0.4.8 + + + (2015-10-05) + + Release on GitHub + + +

+ +
    +
  • Improvement: Avoid hiding exceptions thrown in HttpClient\Request error handlers @arnaud-lb
  • +
+ +
+ +

+ + + 0.4.7 + + + (2015-09-24) + + Release on GitHub + + +

+ +
    +
  • Improvement: Set protocol version on request creation @WyriHaximus
  • +
+ +
+ +

+ + + 0.4.6 + + + (2015-09-20) + + Release on GitHub + + +

+ +
    +
  • Improvement: Support explicitly using HTTP/1.1 protocol version @clue
  • +
+ +
+ +

+ + + 0.4.5 + + + (2015-08-31) + + Release on GitHub + + +

+ +
    +
  • Improvement: Replaced the abandoned guzzle/parser with guzzlehttp/psr7 @WyriHaximus
  • +
+ +
+ +

+ + + 0.4.4 + + + (2015-06-16) + + Release on GitHub + + +

+ +
    +
  • Improvement: Emit drain event when the request is ready to receive more data by @arnaud-lb
  • +
+ +
+ +

+ + + 0.4.3 + + + (2015-06-15) + + Release on GitHub + + +

+ +
    +
  • Improvement: Added support for using auth informations from URL by @arnaud-lb
  • +
+ +
+ +

+ + + 0.4.2 + + + (2015-05-14) + + Release on GitHub + + +

+ +
    +
  • Improvement: Pass Response object on with data emit by @dpovshed
  • +
+ +
+

+ + 2014 +

+ + +

+ + + 0.4.1 + + + (2014-11-23) + + Release on GitHub + + +

+ +
    +
  • Improvement: Use EventEmitterTrait instead of base class by @cursedcoder
  • +
  • Improvement: Changed Stream to DuplexStreamInterface in Response::__construct by @mbonneau
  • +
+ +
+ +

+ + + 0.4.0 + + + (2014-02-02) + + Release on GitHub + + +

+ +
    +
  • BC break: Drop unused Response::getBody()
  • +
  • BC break: Bump minimum PHP version to PHP 5.4, remove 5.3 specific hacks
  • +
  • BC break: Remove $loop argument from HttpClient: Client, Request, Response
  • +
  • BC break: Update to React/Promise 2.0
  • +
  • Dependency: Autoloading and filesystem structure now PSR-4 instead of PSR-0
  • +
  • Bump React dependencies to v0.4
  • +
+ +
+

+ + 2013 +

+ + +

+ + + 0.3.1 + + + (2013-04-21) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Correct requirement for socket-client
  • +
+ +
+ +

+ + + 0.3.0 + + + (2013-04-14) + + Release on GitHub + + +

+ +
    +
  • BC break: Socket connection handling moved to new SocketClient component
  • +
  • Bump React dependencies to v0.3
  • +
+ +
+

+ + 2012 +

+ + +

+ + + 0.2.6 + + + (2012-12-26) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + 0.2.5 + + + (2012-11-26) + + Release on GitHub + + +

+ +
    +
  • Feature: Use a promise-based API internally
  • +
  • Bug fix: Use DNS resolver correctly
  • +
+ +
+ +

+ + + 0.2.3 + + + (2012-11-05) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + 0.2.2 + + + (2012-10-28) + + Release on GitHub + + +

+ + + +
+
+ +
+
+
+ + + + + + diff --git a/http-client/index.html b/http-client/index.html new file mode 100644 index 000000000..9bdf439c1 --- /dev/null +++ b/http-client/index.html @@ -0,0 +1,741 @@ + + + + + + + + HTTPClient: +HttpClient - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

HTTPClient

+ + +

Build Status

+

Event-driven, streaming HTTP client for ReactPHP.

+

Table of Contents

+ +

+Basic usage

+

+Client

+

The Client is responsible for communicating with HTTP servers, managing the +connection state and sending your HTTP requests. +It also registers everything with the main EventLoop.

+
$loop = React\EventLoop\Factory::create();
+$client = new Client($loop);
+

If you need custom connector settings (DNS resolution, TLS parameters, timeouts, +proxy servers etc.), you can explicitly pass a custom instance of the +ConnectorInterface:

+
$connector = new \React\Socket\Connector($loop, array(
+    'dns' => '127.0.0.1',
+    'tcp' => array(
+        'bindto' => '192.168.10.1:0'
+    ),
+    'tls' => array(
+        'verify_peer' => false,
+        'verify_peer_name' => false
+    )
+));
+
+$client = new Client($loop, $connector);
+

The request(string $method, string $uri, array $headers = array(), string $version = '1.0'): Request +method can be used to prepare new Request objects.

+

The optional $headers parameter can be used to pass additional request +headers. +You can use an associative array (key=value) or an array for each header value +(key=values). +The Request will automatically include an appropriate Host, +User-Agent: react/alpha and Connection: close header if applicable. +You can pass custom header values or use an empty array to omit any of these.

+

The Request#write(string $data) method can be used to +write data to the request body. +Data will be buffered until the underlying connection is established, at which +point buffered data will be sent and all further data will be passed to the +underlying connection immediately.

+

The Request#end(?string $data = null) method can be used to +finish sending the request. +You may optionally pass a last request body data chunk that will be sent just +like a write() call. +Calling this method finalizes the outgoing request body (which may be empty). +Data will be buffered until the underlying connection is established, at which +point buffered data will be sent and all further data will be ignored.

+

The Request#close() method can be used to +forefully close sending the request. +Unlike the end() method, this method discards any buffers and closes the +underlying connection if it is already established or cancels the pending +connection attempt otherwise.

+

Request implements WritableStreamInterface, so a Stream can be piped to it. +Interesting events emitted by Request:

+
    +
  • +response: The response headers were received from the server and successfully +parsed. The first argument is a Response instance.
  • +
  • +drain: The outgoing buffer drained and the response is ready to accept more +data for the next write() call.
  • +
  • +error: An error occurred, an Exception is passed as first argument. +If the response emits an error event, this will also be emitted here.
  • +
  • +close: The request is closed. If an error occurred, this event will be +preceeded by an error event. +For a successful response, this will be emitted only once the response emits +the close event.
  • +
+

Response implements ReadableStreamInterface. +Interesting events emitted by Response:

+
    +
  • +data: Passes a chunk of the response body as first argument. +When a response encounters a chunked encoded response it will parse it +transparently for the user and removing the Transfer-Encoding header.
  • +
  • +error: An error occurred, an Exception is passed as first argument. +This will also be forwarded to the request and emit an error event there.
  • +
  • +end: The response has been fully received.
  • +
  • +close: The response is closed. If an error occured, this event will be +preceeded by an error event. +This will also be forwarded to the request and emit a close event there.
  • +
+

+Example

+
<?php
+
+$loop = React\EventLoop\Factory::create();
+$client = new React\HttpClient\Client($loop);
+
+$request = $client->request('GET', 'https://github.com/');
+$request->on('response', function ($response) {
+    $response->on('data', function ($chunk) {
+        echo $chunk;
+    });
+    $response->on('end', function() {
+        echo 'DONE';
+    });
+});
+$request->on('error', function (\Exception $e) {
+    echo $e;
+});
+$request->end();
+$loop->run();
+

See also the examples.

+

+Advanced Usage

+

+Unix domain sockets

+

By default, this library supports transport over plaintext TCP/IP and secure +TLS connections for the http:// and https:// URI schemes respectively. +This library also supports Unix domain sockets (UDS) when explicitly configured.

+

In order to use a UDS path, you have to explicitly configure the connector to +override the destination URI so that the hostname given in the request URI will +no longer be used to establish the connection:

+
$connector = new FixedUriConnector(
+    'unix:///var/run/docker.sock',
+    new UnixConnector($loop)
+);
+
+$client = new Client($loop, $connector);
+
+$request = $client->request('GET', 'http://localhost/info');
+

See also example #11.

+

+Install

+

The recommended way to install this library is through Composer. +New to Composer?

+

This will install the latest supported version:

+
$ composer require react/http-client:^0.5.9
+

See also the CHANGELOG for details about version upgrades.

+

This project aims to run on any platform and thus does not require any PHP +extensions and supports running on legacy PHP 5.3 through current PHP 7+ and +HHVM. +It's highly recommended to use PHP 7+ for this project.

+

+Tests

+

To run the test suite, you first need to clone this repo and then install all +dependencies through Composer:

+
$ composer install
+

To run the test suite, go to the project root and run:

+
$ php vendor/bin/phpunit
+

The test suite also contains a number of functional integration tests that send +test HTTP requests against the online service http://httpbin.org and thus rely +on a stable internet connection. +If you do not want to run these, they can simply be skipped like this:

+
$ php vendor/bin/phpunit --exclude-group internet
+

+License

+

MIT, see LICENSE file.

+
+ +
+
+
+ + + + + + diff --git a/http-client/license.html b/http-client/license.html new file mode 100644 index 000000000..84fa834fd --- /dev/null +++ b/http-client/license.html @@ -0,0 +1,582 @@ + + + + + + + + HTTPClient: License - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

HTTPClient License

+ +

Copyright (c) 2012 Igor Wiedler, Chris Boden

+

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions:

+

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.

+
+ +
+
+
+ + + + + + diff --git a/http/changelog.html b/http/changelog.html new file mode 100644 index 000000000..af2d19540 --- /dev/null +++ b/http/changelog.html @@ -0,0 +1,1467 @@ + + + + + + + + HTTP: Changelog - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

HTTP Changelog

+ + + +

+ + 2018 +

+ + +

+ + + 0.8.3 + + + (2018-04-11) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Do not pause connection stream to detect closed connections immediately.
    +(#315 by @clue)

    +
  • +
  • +

    Feature: Keep incoming Transfer-Encoding: chunked request header.
    +(#316 by @clue)

    +
  • +
  • +

    Feature: Reject invalid requests that contain both Content-Length and Transfer-Encoding request headers.
    +(#318 by @clue)

    +
  • +
  • +

    Minor internal refactoring to simplify connection close logic after sending response.
    +(#317 by @clue)

    +
  • +
+ +
+ +

+ + + 0.8.2 + + + (2018-04-06) + + Release on GitHub + + +

+ +
    +
  • +

    Fix: Do not pass $next handler to final request handler.
    +(#308 by @clue)

    +
  • +
  • +

    Fix: Fix awaiting queued handlers when cancelling a queued handler.
    +(#313 by @clue)

    +
  • +
  • +

    Fix: Fix Server to skip SERVER_ADDR params for Unix domain sockets (UDS).
    +(#307 by @clue)

    +
  • +
  • +

    Documentation for PSR-15 middleware and minor documentation improvements.
    +(#314 by @clue and #297, #298 and #310 by @seregazhuk)

    +
  • +
  • +

    Minor code improvements and micro optimizations.
    +(#301 by @seregazhuk and #305 by @kalessil)

    +
  • +
+ +
+ +

+ + + 0.8.1 + + + (2018-01-05) + + Release on GitHub + + +

+ +
    +
  • +

    Major request handler performance improvement. Benchmarks suggest number of
    +requests/s improved by more than 50% for common GET requests!
    +We now avoid queuing, buffering and wrapping incoming requests in promises
    +when we're below limits and instead can directly process common requests.
    +(#291, #292, #293, #294 and #296 by @clue)

    +
  • +
  • +

    Fix: Fix concurrent invoking next middleware request handlers
    +(#293 by @clue)

    +
  • +
  • +

    Small code improvements
    +(#286 by @seregazhuk)

    +
  • +
  • +

    Improve test suite to be less fragile when using ext-event and
    +fix test suite forward compatibility with upcoming EventLoop releases
    +(#288 and #290 by @clue)

    +
  • +
+ +
+

+ + 2017 +

+ + +

+ + + 0.8.0 + + + (2017-12-12) + + Release on GitHub + + +

+ +
    +
  • +

    Feature / BC break: Add new Server facade that buffers and parses incoming
    +HTTP requests. This provides full PSR-7 compatibility, including support for
    +form submissions with POST fields and file uploads.
    +The old Server has been renamed to StreamingServer for advanced usage
    +and is used internally.
    +(#266, #271, #281, #282, #283 and #284 by @WyriHaximus and @clue)

    +
    // old: handle incomplete/streaming requests
    +$server = new Server($handler);
    +
    +// new: handle complete, buffered and parsed requests
    +// new: full PSR-7 support, including POST fields and file uploads
    +$server = new Server($handler);
    +
    +// new: handle incomplete/streaming requests
    +$server = new StreamingServer($handler);
    +
    +

    While this is technically a small BC break, this should in fact not break
    +most consuming code. If you rely on the old request streaming, you can
    +explicitly use the advanced StreamingServer to restore old behavior.

    +
    +
  • +
  • +

    Feature: Add support for middleware request handler arrays
    +(#215, #228, #229, #236, #237, #238, #246, #247, #277, #279 and #285 by @WyriHaximus, @clue and @jsor)

    +
    // new: middleware request handler arrays
    +$server = new Server(array(
    +    function (ServerRequestInterface $request, callable $next) {
    +        $request = $request->withHeader('Processed', time());
    +        return $next($request);
    +    },
    +    function (ServerRequestInterface $request) {
    +        return new Response();
    +    }
    +));
    +
  • +
  • +

    Feature: Add support for limiting how many next request handlers can be
    +executed concurrently (LimitConcurrentRequestsMiddleware)
    +(#272 by @clue and @WyriHaximus)

    +
    // new: explicitly limit concurrency
    +$server = new Server(array(
    +    new LimitConcurrentRequestsMiddleware(10),
    +    $handler
    +));
    +
  • +
  • +

    Feature: Add support for buffering the incoming request body
    +(RequestBodyBufferMiddleware).
    +This feature mimics PHP's default behavior and respects its post_max_size
    +ini setting by default and allows explicit configuration.
    +(#216, #224, #263, #276 and #278 by @WyriHaximus and #235 by @andig)

    +
    // new: buffer up to 10 requests with 8 MiB each
    +$server = new StreamingServer(array(
    +    new LimitConcurrentRequestsMiddleware(10),
    +    new RequestBodyBufferMiddleware('8M'),
    +    $handler
    +));
    +
  • +
  • +

    Feature: Add support for parsing form submissions with POST fields and file
    +uploads (RequestBodyParserMiddleware).
    +This feature mimics PHP's default behavior and respects its ini settings and
    +MAX_FILE_SIZE POST fields by default and allows explicit configuration.
    +(#220, #226, #252, #261, #264, #265, #267, #268, #274 by @WyriHaximus and @clue)

    +
    // new: buffer up to 10 requests with 8 MiB each
    +// and limit to 4 uploads with 2 MiB each
    +$server = new StreamingServer(array(
    +    new LimitConcurrentRequestsMiddleware(10),
    +    new RequestBodyBufferMiddleware('8M'),
    +    new RequestBodyParserMiddleware('2M', 4)
    +    $handler
    +));
    +
  • +
  • +

    Feature: Update Socket to work around sending secure HTTPS responses with PHP < 7.1.4
    +(#244 by @clue)

    +
  • +
  • +

    Feature: Support sending same response header multiple times (e.g. Set-Cookie)
    +(#248 by @clue)

    +
  • +
  • +

    Feature: Raise maximum request header size to 8k to match common implementations
    +(#253 by @clue)

    +
  • +
  • +

    Improve test suite by adding forward compatibility with PHPUnit 6, test
    +against PHP 7.1 and PHP 7.2 and refactor and remove risky and duplicate tests.
    +(#243, #269 and #270 by @carusogabriel and #249 by @clue)

    +
  • +
  • +

    Minor code refactoring to move internal classes to React\Http\Io namespace
    +and clean up minor code and documentation issues
    +(#251 by @clue, #227 by @kalessil, #240 by @christoph-kluge, #230 by @jsor and #280 by @andig)

    +
  • +
+ +
+ +

+ + + 0.7.4 + + + (2017-08-16) + + Release on GitHub + + +

+ +
    +
  • Improvement: Target evenement 3.0 a long side 2.0 and 1.0
    +(#212 by @WyriHaximus)
  • +
+ +
+ +

+ + + 0.7.3 + + + (2017-08-14) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Support Throwable when setting previous exception from server callback
    +(#155 by @jsor)

    +
  • +
  • +

    Fix: Fixed URI parsing for origin-form requests that contain scheme separator
    +such as /path?param=http://example.com.
    +(#209 by @aaronbonneau)

    +
  • +
  • +

    Improve test suite by locking Travis distro so new defaults will not break the build
    +(#211 by @clue)

    +
  • +
+ +
+ +

+ + + 0.7.2 + + + (2017-07-04) + + Release on GitHub + + +

+ +
    +
  • +

    Fix: Stricter check for invalid request-line in HTTP requests
    +(#206 by @clue)

    +
  • +
  • +

    Refactor to use HTTP response reason phrases from response object
    +(#205 by @clue)

    +
  • +
+ +
+ +

+ + + 0.7.1 + + + (2017-06-17) + + Release on GitHub + + +

+ +
    +
  • +

    Fix: Fix parsing CONNECT request without Host header
    +(#201 by @clue)

    +
  • +
  • +

    Internal preparation for future PSR-7 UploadedFileInterface
    +(#199 by @WyriHaximus)

    +
  • +
+ +
+ +

+ + + 0.7.0 + + + (2017-05-29) + + Release on GitHub + + +

+ +
    +
  • +

    Feature / BC break: Use PSR-7 (http-message) standard and
    +Request-In-Response-Out-style request handler callback.
    +Pass standard PSR-7 ServerRequestInterface and expect any standard
    +PSR-7 ResponseInterface in return for the request handler callback.
    +(#146 and #152 and #170 by @legionth)

    +
    // old
    +$app = function (Request $request, Response $response) {
    +    $response->writeHead(200, array('Content-Type' => 'text/plain'));
    +    $response->end("Hello world!\n");
    +};
    +
    +// new
    +$app = function (ServerRequestInterface $request) {
    +    return new Response(
    +        200,
    +        array('Content-Type' => 'text/plain'),
    +        "Hello world!\n"
    +    );
    +};
    +

    A Content-Length header will automatically be included if the size can be
    +determined from the response body.
    +(#164 by @maciejmrozinski)

    +

    The request handler callback will automatically make sure that responses to
    +HEAD requests and certain status codes, such as 204 (No Content), never
    +contain a response body.
    +(#156 by @clue)

    +

    The intermediary 100 Continue response will automatically be sent if
    +demanded by a HTTP/1.1 client.
    +(#144 by @legionth)

    +

    The request handler callback can now return a standard Promise if
    +processing the request needs some time, such as when querying a database.
    +Similarly, the request handler may return a streaming response if the
    +response body comes from a ReadableStreamInterface or its size is
    +unknown in advance.

    +
    // old
    +$app = function (Request $request, Response $response) use ($db) {
    +    $db->query()->then(function ($result) use ($response) {
    +        $response->writeHead(200, array('Content-Type' => 'text/plain'));
    +        $response->end($result);
    +    });
    +};
    +
    +// new
    +$app = function (ServerRequestInterface $request) use ($db) {
    +    return $db->query()->then(function ($result) {
    +        return new Response(
    +            200,
    +            array('Content-Type' => 'text/plain'),
    +            $result
    +        );
    +    });
    +};
    +

    Pending promies and response streams will automatically be canceled once the
    +client connection closes.
    +(#187 and #188 by @clue)

    +

    The ServerRequestInterface contains the full effective request URI,
    +server-side parameters, query parameters and parsed cookies values as
    +defined in PSR-7.
    +(#167 by @clue and #174, #175 and #180 by @legionth)

    +
    $app = function (ServerRequestInterface $request) {
    +    return new Response(
    +        200,
    +        array('Content-Type' => 'text/plain'),
    +        $request->getUri()->getScheme()
    +    );
    +};
    +

    Advanced: Support duplex stream response for Upgrade requests such as
    +Upgrade: WebSocket or custom protocols and CONNECT requests
    +(#189 and #190 by @clue)

    +
    +

    Note that the request body will currently not be buffered and parsed by
    +default, which depending on your particilar use-case, may limit
    +interoperability with the PSR-7 (http-message) ecosystem.
    +The provided streaming request body interfaces allow you to perform
    +buffering and parsing as needed in the request handler callback.
    +See also the README and examples for more details.

    +
    +
  • +
  • +

    Feature / BC break: Replace request listener with callback function and
    +use listen() method to support multiple listening sockets
    +(#97 by @legionth and #193 by @clue)

    +
    // old
    +$server = new Server($socket);
    +$server->on('request', $app);
    +
    +// new
    +$server = new Server($app);
    +$server->listen($socket);
    +
  • +
  • +

    Feature: Support the more advanced HTTP requests, such as
    +OPTIONS * HTTP/1.1 (OPTIONS method in asterisk-form),
    +GET http://example.com/path HTTP/1.1 (plain proxy requests in absolute-form),
    +CONNECT example.com:443 HTTP/1.1 (CONNECT proxy requests in authority-form)
    +and sanitize Host header value across all requests.
    +(#157, #158, #161, #165, #169 and #173 by @clue)

    +
  • +
  • +

    Feature: Forward compatibility with Socket v1.0, v0.8, v0.7 and v0.6 and
    +forward compatibility with Stream v1.0 and v0.7
    +(#154, #163, #183, #184 and #191 by @clue)

    +
  • +
  • +

    Feature: Simplify examples to ease getting started and
    +add benchmarking example
    +(#151 and #162 by @clue)

    +
  • +
  • +

    Improve test suite by adding tests for case insensitive chunked transfer
    +encoding and ignoring HHVM test failures until Travis tests work again.
    +(#150 by @legionth and #185 by @clue)

    +
  • +
+ +
+ +

+ + + 0.6.0 + + + (2017-03-09) + + Release on GitHub + + +

+ +
    +
  • +

    Feature / BC break: The Request and Response objects now follow strict
    +stream semantics and their respective methods and events.
    +(#116, #129, #133, #135, #136, #137, #138, #140, #141 by @legionth
    +and #122, #123, #130, #131, #132, #142 by @clue)

    +

    This implies that the Server now supports proper detection of the request
    +message body stream, such as supporting decoding chunked transfer encoding,
    +delimiting requests with an explicit Content-Length header
    +and those with an empty request message body.

    +

    These streaming semantics are compatible with previous Stream v0.5, future
    +compatible with v0.5 and upcoming v0.6 versions and can be used like this:

    +
    $http->on('request', function (Request $request, Response $response) {
    +    $contentLength = 0;
    +    $request->on('data', function ($data) use (&$contentLength) {
    +        $contentLength += strlen($data);
    +    });
    +
    +    $request->on('end', function () use ($response, &$contentLength){
    +        $response->writeHead(200, array('Content-Type' => 'text/plain'));
    +        $response->end("The length of the submitted request body is: " . $contentLength);
    +    });
    +
    +    // an error occured
    +    // e.g. on invalid chunked encoded data or an unexpected 'end' event 
    +    $request->on('error', function (\Exception $exception) use ($response, &$contentLength) {
    +        $response->writeHead(400, array('Content-Type' => 'text/plain'));
    +        $response->end("An error occured while reading at length: " . $contentLength);
    +    });
    +});
    +

    Similarly, the Request and Response now strictly follow the
    +close() method and close event semantics.
    +Closing the Request does not interrupt the underlying TCP/IP in
    +order to allow still sending back a valid response message.
    +Closing the Response does terminate the underlying TCP/IP
    +connection in order to clean up resources.

    +

    You should make sure to always attach a request event listener
    +like above. The Server will not respond to an incoming HTTP
    +request otherwise and keep the TCP/IP connection pending until the
    +other side chooses to close the connection.

    +
  • +
  • +

    Feature: Support HTTP/1.1 and HTTP/1.0 for Request and Response.
    +(#124, #125, #126, #127, #128 by @clue and #139 by @legionth)

    +

    The outgoing Response will automatically use the same HTTP version as the
    +incoming Request message and will only apply HTTP/1.1 semantics if
    +applicable. This includes that the Response will automatically attach a
    +Date and Connection: close header if applicable.

    +

    This implies that the Server now automatically responds with HTTP error
    +messages for invalid requests (status 400) and those exceeding internal
    +request header limits (status 431).

    +
  • +
+ +
+ +

+ + + 0.5.0 + + + (2017-02-16) + + Release on GitHub + + +

+ +
    +
  • +

    Feature / BC break: Change Request methods to be in line with PSR-7
    +(#117 by @clue)

    +
      +
    • Rename getQuery() to getQueryParams()
    • +
    • Rename getHttpVersion() to getProtocolVersion()
    • +
    • Change getHeaders() to always return an array of string values
      +for each header
    • +
    +
  • +
  • +

    Feature / BC break: Update Socket component to v0.5 and
    +add secure HTTPS server support
    +(#90 and #119 by @clue)

    +
    // old plaintext HTTP server
    +$socket = new React\Socket\Server($loop);
    +$socket->listen(8080, '127.0.0.1');
    +$http = new React\Http\Server($socket);
    +
    +// new plaintext HTTP server
    +$socket = new React\Socket\Server('127.0.0.1:8080', $loop);
    +$http = new React\Http\Server($socket);
    +
    +// new secure HTTPS server
    +$socket = new React\Socket\Server('127.0.0.1:8080', $loop);
    +$socket = new React\Socket\SecureServer($socket, $loop, array(
    +    'local_cert' => __DIR__ . '/localhost.pem'
    +));
    +$http = new React\Http\Server($socket);
    +
  • +
  • +

    BC break: Mark internal APIs as internal or private and
    +remove unneeded ServerInterface
    +(#118 by @clue, #95 by @legionth)

    +
  • +
+ +
+ +

+ + + 0.4.4 + + + (2017-02-13) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Add request header accessors (à la PSR-7)
    +(#103 by @clue)

    +
    // get value of host header
    +$host = $request->getHeaderLine('Host');
    +
    +// get list of all cookie headers
    +$cookies = $request->getHeader('Cookie');
    +
  • +
  • +

    Feature: Forward pause() and resume() from Request to underlying connection
    +(#110 by @clue)

    +
    // support back-pressure when piping request into slower destination
    +$request->pipe($dest);
    +
    +// manually pause/resume request
    +$request->pause();
    +$request->resume();
    +
  • +
  • +

    Fix: Fix 100-continue to be handled case-insensitive and ignore it for HTTP/1.0.
    +Similarly, outgoing response headers are now handled case-insensitive, e.g
    +we no longer apply chunked transfer encoding with mixed-case Content-Length.
    +(#107 by @clue)

    +
    // now handled case-insensitive
    +$request->expectsContinue();
    +
    +// now works just like properly-cased header
    +$response->writeHead($status, array('content-length' => 0));
    +
  • +
  • +

    Fix: Do not emit empty data events and ignore empty writes in order to
    +not mess up chunked transfer encoding
    +(#108 and #112 by @clue)

    +
  • +
  • +

    Lock and test minimum required dependency versions and support PHPUnit v5
    +(#113, #115 and #114 by @andig)

    +
  • +
+ +
+ +

+ + + 0.4.3 + + + (2017-02-10) + + Release on GitHub + + +

+ +
    +
  • Fix: Do not take start of body into account when checking maximum header size
    +(#88 by @nopolabs)
  • +
  • Fix: Remove data listener if HeaderParser emits an error
    +(#83 by @nick4fake)
  • +
  • First class support for PHP 5.3 through PHP 7 and HHVM
    +(#101 and #102 by @clue, #66 by @WyriHaximus)
  • +
  • Improve test suite by adding PHPUnit to require-dev,
    +improving forward compatibility with newer PHPUnit versions
    +and replacing unneeded test stubs
    +(#92 and #93 by @nopolabs, #100 by @legionth)
  • +
+ +
+

+ + 2016 +

+ + +

+ + + 0.4.2 + + + (2016-11-09) + + Release on GitHub + + +

+ + + +
+

+ + 2015 +

+ + +

+ + + 0.4.1 + + + (2015-05-21) + + Release on GitHub + + +

+ +
    +
  • Replaced guzzle/parser with guzzlehttp/psr7 by @cboden
  • +
  • FIX Continue Header by @iannsp
  • +
  • Missing type hint by @marenzo
  • +
+ +
+

+ + 2014 +

+ + +

+ + + 0.4.0 + + + (2014-02-02) + + Release on GitHub + + +

+ +
    +
  • BC break: Bump minimum PHP version to PHP 5.4, remove 5.3 specific hacks
  • +
  • BC break: Update to React/Promise 2.0
  • +
  • BC break: Update to Evenement 2.0
  • +
  • Dependency: Autoloading and filesystem structure now PSR-4 instead of PSR-0
  • +
  • Bump React dependencies to v0.4
  • +
+ +
+

+ + 2013 +

+ + +

+ + + 0.3.0 + + + (2013-02-24) + + Release on GitHub + + +

+ +
    +
  • Bump React dependencies to v0.3
  • +
+ +
+

+ + 2012 +

+ + +

+ + + 0.2.6 + + + (2012-12-26) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Emit end event when Response closes (@beaucollins)
  • +
+ +
+ +

+ + + 0.2.3 + + + (2012-11-10) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Forward drain events from HTTP response (@cs278)
  • +
  • Dependency: Updated guzzle deps to 3.0.*
  • +
+ +
+ +

+ + + 0.2.2 + + + (2012-10-28) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + 0.2.1 + + + (2012-10-02) + + Release on GitHub + + +

+ +
    +
  • Feature: Support HTTP 1.1 continue
  • +
+ +
+ +

+ + + 0.2.0 + + + (2012-09-10) + + Release on GitHub + + +

+ +
    +
  • Bump React dependencies to v0.2
  • +
+ +
+ +

+ + + 0.1.1 + + + (2012-07-12) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + 0.1.0 + + + (2012-07-11) + + Release on GitHub + + +

+ +
    +
  • First tagged release
  • +
+ +
+
+ +
+
+
+ + + + + + diff --git a/http/index.html b/http/index.html new file mode 100644 index 000000000..141eee59f --- /dev/null +++ b/http/index.html @@ -0,0 +1,1575 @@ + + + + + + + + HTTP: +Http - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

HTTP

+ + +

Build Status

+

Event-driven, streaming plaintext HTTP and secure HTTPS server for ReactPHP.

+

Table of Contents

+ +

+Quickstart example

+

This is an HTTP server which responds with Hello World! to every request.

+
$loop = React\EventLoop\Factory::create();
+
+$server = new Server(function (ServerRequestInterface $request) {
+    return new Response(
+        200,
+        array(
+            'Content-Type' => 'text/plain'
+        ),
+        "Hello World!\n"
+    );
+});
+
+$socket = new React\Socket\Server(8080, $loop);
+$server->listen($socket);
+
+$loop->run();
+

See also the examples.

+

+Usage

+

+Server

+

The Server class is responsible for handling incoming connections and then +processing each incoming HTTP request.

+

It buffers and parses the complete incoming HTTP request in memory. Once the +complete request has been received, it will invoke the request handler.

+

For each request, it executes the callback function passed to the +constructor with the respective request object and expects +a respective response object in return.

+
$server = new Server(function (ServerRequestInterface $request) {
+    return new Response(
+        200,
+        array(
+            'Content-Type' => 'text/plain'
+        ),
+        "Hello World!\n"
+    );
+});
+

For most users a server that buffers and parses a requests before handling it over as a +PSR-7 request is what they want. The Server facade takes care of that, and takes the more +advanced configuration out of hand. Under the hood it uses StreamingServer +with the the three stock middleware using default settings from php.ini.

+

The LimitConcurrentRequestsMiddleware requires a limit, +as such the Server facade uses the memory_limit and post_max_size ini settings to +calculate a sensible limit. It assumes a maximum of a quarter of the memory_limit for +buffering and the other three quarter for parsing and handling the requests. The limit is +division of half of memory_limit by memory_limit rounded up.

+
+

Note that any errors emitted by the wrapped StreamingServer are forwarded by Server.

+
+

+StreamingServer

+

The advanced StreamingServer class is responsible for handling incoming connections and then +processing each incoming HTTP request.

+

Unlike the Server class, it does not buffer and parse the incoming +HTTP request body by default. This means that the request handler will be +invoked with a streaming request body.

+

For each request, it executes the callback function passed to the +constructor with the respective request object and expects +a respective response object in return.

+
$server = new StreamingServer(function (ServerRequestInterface $request) {
+    return new Response(
+        200,
+        array(
+            'Content-Type' => 'text/plain'
+        ),
+        "Hello World!\n"
+    );
+});
+

In order to process any connections, the server needs to be attached to an +instance of React\Socket\ServerInterface which emits underlying streaming +connections in order to then parse incoming data as HTTP.

+

You can attach this to a +React\Socket\Server +in order to start a plaintext HTTP server like this:

+
$server = new StreamingServer($handler);
+
+$socket = new React\Socket\Server(8080, $loop);
+$server->listen($socket);
+

See also the listen() method and the first example for more details.

+

Similarly, you can also attach this to a +React\Socket\SecureServer +in order to start a secure HTTPS server like this:

+
$server = new StreamingServer($handler);
+
+$socket = new React\Socket\Server(8080, $loop);
+$socket = new React\Socket\SecureServer($socket, $loop, array(
+    'local_cert' => __DIR__ . '/localhost.pem'
+));
+
+$server->listen($socket);
+

See also example #11 for more details.

+

When HTTP/1.1 clients want to send a bigger request body, they MAY send only +the request headers with an additional Expect: 100-continue header and +wait before sending the actual (large) message body. +In this case the server will automatically send an intermediary +HTTP/1.1 100 Continue response to the client. +This ensures you will receive the request body without a delay as expected. +The Response still needs to be created as described in the +examples above.

+

See also request and response +for more details (e.g. the request data body).

+

The StreamingServer supports both HTTP/1.1 and HTTP/1.0 request messages. +If a client sends an invalid request message, uses an invalid HTTP protocol +version or sends an invalid Transfer-Encoding in the request header, it will +emit an error event, send an HTTP error response to the client and +close the connection:

+
$server->on('error', function (Exception $e) {
+    echo 'Error: ' . $e->getMessage() . PHP_EOL;
+});
+

The server will also emit an error event if you return an invalid +type in the callback function or have a unhandled Exception or Throwable. +If your callback function throws an Exception or Throwable, +the StreamingServer will emit a RuntimeException and add the thrown exception +as previous:

+
$server->on('error', function (Exception $e) {
+    echo 'Error: ' . $e->getMessage() . PHP_EOL;
+    if ($e->getPrevious() !== null) {
+        $previousException = $e->getPrevious();
+        echo $previousException->getMessage() . PHP_EOL;
+    }
+});
+

Note that the request object can also emit an error. +Check out request for more details.

+

+Request

+

As seen above, the Server and StreamingServer +classes are responsible for handling incoming connections and then processing +each incoming HTTP request.

+

The request object will be processed once the request has +been received by the client. +This request object implements the +PSR-7 ServerRequestInterface +which in turn extends the +PSR-7 RequestInterface +and will be passed to the callback function like this.

+
$server = new Server(function (ServerRequestInterface $request) {
+   $body = "The method of the request is: " . $request->getMethod();
+   $body .= "The requested path is: " . $request->getUri()->getPath();
+
+   return new Response(
+       200,
+       array(
+           'Content-Type' => 'text/plain'
+       ),
+       $body
+   );
+});
+

For more details about the request object, also check out the documentation of +PSR-7 ServerRequestInterface +and +PSR-7 RequestInterface.

+

+Request parameters

+

The getServerParams(): mixed[] method can be used to +get server-side parameters similar to the $_SERVER variable. +The following parameters are currently available:

+
    +
  • +REMOTE_ADDR +The IP address of the request sender
  • +
  • +REMOTE_PORT +Port of the request sender
  • +
  • +SERVER_ADDR +The IP address of the server
  • +
  • +SERVER_PORT +The port of the server
  • +
  • +REQUEST_TIME +Unix timestamp when the complete request header has been received, +as integer similar to time() +
  • +
  • +REQUEST_TIME_FLOAT +Unix timestamp when the complete request header has been received, +as float similar to microtime(true) +
  • +
  • +HTTPS +Set to 'on' if the request used HTTPS, otherwise it won't be set
  • +
+
$server = new Server(function (ServerRequestInterface $request) {
+    $body = "Your IP is: " . $request->getServerParams()['REMOTE_ADDR'];
+
+    return new Response(
+        200,
+        array(
+            'Content-Type' => 'text/plain'
+        ),
+        $body
+    );
+});
+

See also example #3.

+
+

Advanced: Note that address parameters will not be set if you're listening on +a Unix domain socket (UDS) path as this protocol lacks the concept of +host/port.

+
+

+Query parameters

+

The getQueryParams(): array method can be used to get the query parameters +similiar to the $_GET variable.

+
$server = new Server(function (ServerRequestInterface $request) {
+    $queryParams = $request->getQueryParams();
+
+    $body = 'The query parameter "foo" is not set. Click the following link ';
+    $body .= '<a href="/?foo=bar">to use query parameter in your request</a>';
+
+    if (isset($queryParams['foo'])) {
+        $body = 'The value of "foo" is: ' . htmlspecialchars($queryParams['foo']);
+    }
+
+    return new Response(
+        200,
+        array(
+            'Content-Type' => 'text/html'
+        ),
+        $body
+    );
+});
+

The response in the above example will return a response body with a link. +The URL contains the query parameter foo with the value bar. +Use htmlentities +like in this example to prevent +Cross-Site Scripting (abbreviated as XSS).

+

See also example #4.

+

+Streaming request

+

If you're using the Server, then the request object will be +buffered and parsed in memory and contains the full request body. +This includes the parsed request body and any file uploads.

+

If you're using the advanced StreamingServer, the +request object will be processed once the request headers have been received. +This means that this happens irrespective of (i.e. before) receiving the +(potentially much larger) request body.

+

While this may be uncommon in the PHP ecosystem, this is actually a very powerful +approach that gives you several advantages not otherwise possible:

+
    +
  • React to requests before receiving a large request body, +such as rejecting an unauthenticated request or one that exceeds allowed +message lengths (file uploads).
  • +
  • Start processing parts of the request body before the remainder of the request +body arrives or if the sender is slowly streaming data.
  • +
  • Process a large request body without having to buffer anything in memory, +such as accepting a huge file upload or possibly unlimited request body stream.
  • +
+

The getBody() method can be used to access the request body stream. +In the default streaming mode, this method returns a stream instance that implements both the +PSR-7 StreamInterface +and the ReactPHP ReadableStreamInterface. +However, most of the PSR-7 StreamInterface methods have been +designed under the assumption of being in control of the request body. +Given that this does not apply to this server, the following +PSR-7 StreamInterface methods are not used and SHOULD NOT be called: +tell(), eof(), seek(), rewind(), write() and read(). +If this is an issue for your use case and/or you want to access uploaded files, +it's highly recommended to use the +RequestBodyBufferMiddleware instead. +The ReactPHP ReadableStreamInterface gives you access to the incoming +request body as the individual chunks arrive:

+
$server = new StreamingServer(function (ServerRequestInterface $request) {
+    return new Promise(function ($resolve, $reject) use ($request) {
+        $contentLength = 0;
+        $request->getBody()->on('data', function ($data) use (&$contentLength) {
+            $contentLength += strlen($data);
+        });
+
+        $request->getBody()->on('end', function () use ($resolve, &$contentLength){
+            $response = new Response(
+                200,
+                array(
+                    'Content-Type' => 'text/plain'
+                ),
+                "The length of the submitted request body is: " . $contentLength
+            );
+            $resolve($response);
+        });
+
+        // an error occures e.g. on invalid chunked encoded data or an unexpected 'end' event
+        $request->getBody()->on('error', function (\Exception $exception) use ($resolve, &$contentLength) {
+            $response = new Response(
+                400,
+                array(
+                    'Content-Type' => 'text/plain'
+                ),
+                "An error occured while reading at length: " . $contentLength
+            );
+            $resolve($response);
+        });
+    });
+});
+

The above example simply counts the number of bytes received in the request body. +This can be used as a skeleton for buffering or processing the request body.

+

See also example #9 for more details.

+

The data event will be emitted whenever new data is available on the request +body stream. +The server also automatically takes care of decoding any incoming requests using +Transfer-Encoding: chunked and will only emit the actual payload as data.

+

The end event will be emitted when the request body stream terminates +successfully, i.e. it was read until its expected end.

+

The error event will be emitted in case the request stream contains invalid +data for Transfer-Encoding: chunked or when the connection closes before +the complete request stream has been received. +The server will automatically stop reading from the connection and discard all +incoming data instead of closing it. +A response message can still be sent (unless the connection is already closed).

+

A close event will be emitted after an error or end event.

+

For more details about the request body stream, check out the documentation of +ReactPHP ReadableStreamInterface.

+

The getSize(): ?int method can be used if you only want to know the request +body size. +This method returns the complete size of the request body as defined by the +message boundaries. +This value may be 0 if the request message does not contain a request body +(such as a simple GET request). +Note that this value may be null if the request body size is unknown in +advance because the request message uses Transfer-Encoding: chunked.

+
$server = new StreamingServer(function (ServerRequestInterface $request) {
+    $size = $request->getBody()->getSize();
+    if ($size === null) {
+        $body = 'The request does not contain an explicit length.';
+        $body .= 'This example does not accept chunked transfer encoding.';
+
+        return new Response(
+            411,
+            array(
+                'Content-Type' => 'text/plain'
+            ),
+            $body
+        );
+    }
+
+    return new Response(
+        200,
+        array(
+            'Content-Type' => 'text/plain'
+        ),
+        "Request body size: " . $size . " bytes\n"
+    );
+});
+

+Request method

+

Note that the server supports any request method (including custom and non- +standard ones) and all request-target formats defined in the HTTP specs for each +respective method, including normal origin-form requests as well as +proxy requests in absolute-form and authority-form. +The getUri(): UriInterface method can be used to get the effective request +URI which provides you access to individiual URI components. +Note that (depending on the given request-target) certain URI components may +or may not be present, for example the getPath(): string method will return +an empty string for requests in asterisk-form or authority-form. +Its getHost(): string method will return the host as determined by the +effective request URI, which defaults to the local socket address if a HTTP/1.0 +client did not specify one (i.e. no Host header). +Its getScheme(): string method will return http or https depending +on whether the request was made over a secure TLS connection to the target host.

+

The Host header value will be sanitized to match this host component plus the +port component only if it is non-standard for this URI scheme.

+

You can use getMethod(): string and getRequestTarget(): string to +check this is an accepted request and may want to reject other requests with +an appropriate error code, such as 400 (Bad Request) or 405 (Method Not +Allowed).

+
+

The CONNECT method is useful in a tunneling setup (HTTPS proxy) and not +something most HTTP servers would want to care about. +Note that if you want to handle this method, the client MAY send a different +request-target than the Host header value (such as removing default ports) +and the request-target MUST take precendence when forwarding.

+
+

+Cookie parameters

+

The getCookieParams(): string[] method can be used to +get all cookies sent with the current request.

+
$server = new Server(function (ServerRequestInterface $request) {
+    $key = 'react\php';
+
+    if (isset($request->getCookieParams()[$key])) {
+        $body = "Your cookie value is: " . $request->getCookieParams()[$key];
+
+        return new Response(
+            200,
+            array(
+                'Content-Type' => 'text/plain'
+            ),
+            $body
+        );
+    }
+
+    return new Response(
+        200,
+        array(
+            'Content-Type' => 'text/plain',
+            'Set-Cookie' => urlencode($key) . '=' . urlencode('test;more')
+        ),
+        "Your cookie has been set."
+    );
+});
+

The above example will try to set a cookie on first access and +will try to print the cookie value on all subsequent tries. +Note how the example uses the urlencode() function to encode +non-alphanumeric characters. +This encoding is also used internally when decoding the name and value of cookies +(which is in line with other implementations, such as PHP's cookie functions).

+

See also example #5 for more details.

+

+Response

+

The callback function passed to the constructor of the Server or +advanced StreamingServer is responsible for processing the request +and returning a response, which will be delivered to the client. +This function MUST return an instance implementing +PSR-7 ResponseInterface +object or a +ReactPHP Promise +which will resolve a PSR-7 ResponseInterface object.

+

You will find a Response class +which implements the PSR-7 ResponseInterface in this project. +We use instantiation of this class in our projects, +but feel free to use any implemantation of the +PSR-7 ResponseInterface you prefer.

+
$server = new Server(function (ServerRequestInterface $request) {
+    return new Response(
+        200,
+        array(
+            'Content-Type' => 'text/plain'
+        ),
+        "Hello World!\n"
+    );
+});
+

+Deferred response

+

The example above returns the response directly, because it needs +no time to be processed. +Using a database, the file system or long calculations +(in fact every action that will take >=1ms) to create your +response, will slow down the server. +To prevent this you SHOULD use a +ReactPHP Promise. +This example shows how such a long-term action could look like:

+
$server = new Server(function (ServerRequestInterface $request) use ($loop) {
+    return new Promise(function ($resolve, $reject) use ($loop) {
+        $loop->addTimer(1.5, function() use ($resolve) {
+            $response = new Response(
+                200,
+                array(
+                    'Content-Type' => 'text/plain'
+                ),
+                "Hello world"
+            );
+            $resolve($response);
+        });
+    });
+});
+

The above example will create a response after 1.5 second. +This example shows that you need a promise, +if your response needs time to created. +The ReactPHP Promise will resolve in a Response object when the request +body ends. +If the client closes the connection while the promise is still pending, the +promise will automatically be cancelled. +The promise cancellation handler can be used to clean up any pending resources +allocated in this case (if applicable). +If a promise is resolved after the client closes, it will simply be ignored.

+

+Streaming response

+

The Response class in this project supports to add an instance which implements the +ReactPHP ReadableStreamInterface +for the response body. +So you are able stream data directly into the response body. +Note that other implementations of the PSR-7 ResponseInterface likely +only support strings.

+
$server = new Server(function (ServerRequestInterface $request) use ($loop) {
+    $stream = new ThroughStream();
+
+    $timer = $loop->addPeriodicTimer(0.5, function () use ($stream) {
+        $stream->emit('data', array(microtime(true) . PHP_EOL));
+    });
+
+    $loop->addTimer(5, function() use ($loop, $timer, $stream) {
+        $loop->cancelTimer($timer);
+        $stream->emit('end');
+    });
+
+    return new Response(
+        200,
+        array(
+            'Content-Type' => 'text/plain'
+        ),
+        $stream
+    );
+});
+

The above example will emit every 0.5 seconds the current Unix timestamp +with microseconds as float to the client and will end after 5 seconds. +This is just a example you could use of the streaming, +you could also send a big amount of data via little chunks +or use it for body data that needs to calculated.

+

If the request handler resolves with a response stream that is already closed, +it will simply send an empty response body. +If the client closes the connection while the stream is still open, the +response stream will automatically be closed. +If a promise is resolved with a streaming body after the client closes, the +response stream will automatically be closed. +The close event can be used to clean up any pending resources allocated +in this case (if applicable).

+
+

Note that special care has to be taken if you use a body stream instance that +implements ReactPHP's +DuplexStreamInterface +(such as the ThroughStream in the above example).

+

For most cases, this will simply only consume its readable side and forward +(send) any data that is emitted by the stream, thus entirely ignoring the +writable side of the stream. +If however this is either a 101 (Switching Protocols) response or a 2xx +(Successful) response to a CONNECT method, it will also write data to the +writable side of the stream. +This can be avoided by either rejecting all requests with the CONNECT +method (which is what most normal origin HTTP servers would likely do) or +or ensuring that only ever an instance of ReadableStreamInterface is +used.

+

The 101 (Switching Protocols) response code is useful for the more advanced +Upgrade requests, such as upgrading to the WebSocket protocol or +implementing custom protocol logic that is out of scope of the HTTP specs and +this HTTP library. +If you want to handle the Upgrade: WebSocket header, you will likely want +to look into using Ratchet instead. +If you want to handle a custom protocol, you will likely want to look into the +HTTP specs and also see +examples #31 and #32 for more details. +In particular, the 101 (Switching Protocols) response code MUST NOT be used +unless you send an Upgrade response header value that is also present in +the corresponding HTTP/1.1 Upgrade request header value. +The server automatically takes care of sending a Connection: upgrade +header value in this case, so you don't have to.

+

The CONNECT method is useful in a tunneling setup (HTTPS proxy) and not +something most origin HTTP servers would want to care about. +The HTTP specs define an opaque "tunneling mode" for this method and make no +use of the message body. +For consistency reasons, this library uses a DuplexStreamInterface in the +response body for tunneled application data. +This implies that that a 2xx (Successful) response to a CONNECT request +can in fact use a streaming response body for the tunneled application data, +so that any raw data the client sends over the connection will be piped +through the writable stream for consumption. +Note that while the HTTP specs make no use of the request body for CONNECT +requests, one may still be present. Normal request body processing applies +here and the connection will only turn to "tunneling mode" after the request +body has been processed (which should be empty in most cases). +See also example #22 for more details.

+
+

+Response length

+

If the response body is a string, a Content-Length header will be added +automatically.

+

If the response body is a ReactPHP ReadableStreamInterface and you do not +specify a Content-Length header, outgoing HTTP/1.1 response messages will +automatically use Transfer-Encoding: chunked and send the respective header +automatically. +The server is responsible for handling Transfer-Encoding, so you SHOULD NOT +pass this header yourself.

+

If you know the length of your stream body, you MAY specify it like this instead:

+
$stream = new ThroughStream();
+$server = new Server(function (ServerRequestInterface $request) use ($stream) {
+    return new Response(
+        200,
+        array(
+            'Content-Length' => '5',
+            'Content-Type' => 'text/plain',
+        ),
+        $stream
+    );
+});
+

Any response to a HEAD request and any response with a 1xx (Informational), +204 (No Content) or 304 (Not Modified) status code will not include a +message body as per the HTTP specs. +This means that your callback does not have to take special care of this and any +response body will simply be ignored.

+

Similarly, any 2xx (Successful) response to a CONNECT request, any response +with a 1xx (Informational) or 204 (No Content) status code will not +include a Content-Length or Transfer-Encoding header as these do not apply +to these messages. +Note that a response to a HEAD request and any response with a 304 (Not +Modified) status code MAY include these headers even though +the message does not contain a response body, because these header would apply +to the message if the same request would have used an (unconditional) GET.

+

+Invalid response

+

An invalid return value or an unhandled Exception or Throwable in the code +of the callback function, will result in an 500 Internal Server Error message. +Make sure to catch Exceptions or Throwables to create own response messages.

+

+Default response headers

+

After the return in the callback function the response will be processed by the +Server or StreamingServer respectively. +They will add the protocol version of the request, so you don't have to.

+

A Date header will be automatically added with the system date and time if none is given. +You can add a custom Date header yourself like this:

+
$server = new Server(function (ServerRequestInterface $request) {
+    return new Response(
+        200,
+        array(
+            'Date' => date('D, d M Y H:i:s T')
+        )
+    );
+});
+

If you don't have a appropriate clock to rely on, you should +unset this header with an empty string:

+
$server = new Server(function (ServerRequestInterface $request) {
+    return new Response(
+        200,
+        array(
+            'Date' => ''
+        )
+    );
+});
+

Note that it will automatically assume a X-Powered-By: react/alpha header +unless your specify a custom X-Powered-By header yourself:

+
$server = new Server(function (ServerRequestInterface $request) {
+    return new Response(
+        200,
+        array(
+            'X-Powered-By' => 'PHP 3'
+        )
+    );
+});
+

If you do not want to send this header at all, you can use an empty string as +value like this:

+
$server = new Server(function (ServerRequestInterface $request) {
+    return new Response(
+        200,
+        array(
+            'X-Powered-By' => ''
+        )
+    );
+});
+

Note that persistent connections (Connection: keep-alive) are currently +not supported. +As such, HTTP/1.1 response messages will automatically include a +Connection: close header, irrespective of what header values are +passed explicitly.

+

+Middleware

+

As documented above, the Server and advanced +StreamingServer accept a single +request handler argument that is responsible for processing an incoming +HTTP request and then creating and returning an outgoing HTTP response.

+

Many common use cases involve validating, processing, manipulating the incoming +HTTP request before passing it to the final business logic request handler. +As such, this project supports the concept of middleware request handlers.

+

A middleware request handler is expected to adhere the following rules:

+
    +
  • It is a valid callable.
  • +
  • It accepts ServerRequestInterface as first argument and an optional +callable as second argument.
  • +
  • It returns either: +
      +
    • An instance implementing ResponseInterface for direct consumption.
    • +
    • Any promise which can be consumed by +Promise\resolve() resolving to a +ResponseInterface for deferred consumption.
    • +
    • It MAY throw an Exception (or return a rejected promise) in order to +signal an error condition and abort the chain.
    • +
    +
  • +
  • It calls $next($request) to continue processing the next middleware +request handler or returns explicitly without calling $next to +abort the chain. +
      +
    • The $next request handler (recursively) invokes the next request +handler from the chain with the same logic as above and returns (or throws) +as above.
    • +
    • The $request may be modified prior to calling $next($request) to +change the incoming request the next middleware operates on.
    • +
    • The $next return value may be consumed to modify the outgoing response.
    • +
    • The $next request handler MAY be called more than once if you want to +implement custom "retry" logic etc.
    • +
    +
  • +
+

Note that this very simple definition allows you to use either anonymous +functions or any classes that use the magic __invoke() method. +This allows you to easily create custom middleware request handlers on the fly +or use a class based approach to ease using existing middleware implementations.

+

While this project does provide the means to use middleware implementations, +it does not aim to define how middleware implementations should look like. +We realize that there's a vivid ecosystem of middleware implementations and +ongoing effort to standardize interfaces between these with +PSR-15 (HTTP Server Request Handlers) +and support this goal. +As such, this project only bundles a few middleware implementations that are +required to match PHP's request behavior (see below) and otherwise actively +encourages Third-Party Middleware implementations.

+

In order to use middleware request handlers, simply pass an array with all +callables as defined above to the Server or +StreamingServer respectively. +The following example adds a middleware request handler that adds the current time to the request as a +header (Request-Time) and a final request handler that always returns a 200 code without a body:

+
$server = new Server(array(
+    function (ServerRequestInterface $request, callable $next) {
+        $request = $request->withHeader('Request-Time', time());
+        return $next($request);
+    },
+    function (ServerRequestInterface $request) {
+        return new Response(200);
+    }
+));
+
+

Note how the middleware request handler and the final request handler have a +very simple (and similar) interface. The only difference is that the final +request handler does not receive a $next handler.

+
+

Similarly, you can use the result of the $next middleware request handler +function to modify the outgoing response. +Note that as per the above documentation, the $next middleware request handler may return a +ResponseInterface directly or one wrapped in a promise for deferred +resolution. +In order to simplify handling both paths, you can simply wrap this in a +Promise\resolve() call like this:

+
$server = new Server(array(
+    function (ServerRequestInterface $request, callable $next) {
+        $promise = React\Promise\resolve($next($request));
+        return $promise->then(function (ResponseInterface $response) {
+            return $response->withHeader('Content-Type', 'text/html');
+        });
+    },
+    function (ServerRequestInterface $request) {
+        return new Response(200);
+    }
+));
+

Note that the $next middleware request handler may also throw an +Exception (or return a rejected promise) as described above. +The previous example does not catch any exceptions and would thus signal an +error condition to the Server. +Alternatively, you can also catch any Exception to implement custom error +handling logic (or logging etc.) by wrapping this in a +Promise like this:

+
$server = new Server(array(
+    function (ServerRequestInterface $request, callable $next) {
+        $promise = new React\Promise\Promise(function ($resolve) use ($next, $request) {
+            $resolve($next($request));
+        });
+        return $promise->then(null, function (Exception $e) {
+            return new Response(
+                500,
+                array(),
+                'Internal error: ' . $e->getMessage()
+            );
+        });
+    },
+    function (ServerRequestInterface $request) {
+        if (mt_rand(0, 1) === 1) {
+            throw new RuntimeException('Database error');
+        }
+        return new Response(200);
+    }
+));
+

+LimitConcurrentRequestsMiddleware

+

The LimitConcurrentRequestsMiddleware can be used to +limit how many next handlers can be executed concurrently.

+

If this middleware is invoked, it will check if the number of pending +handlers is below the allowed limit and then simply invoke the next handler +and it will return whatever the next handler returns (or throws).

+

If the number of pending handlers exceeds the allowed limit, the request will +be queued (and its streaming body will be paused) and it will return a pending +promise. +Once a pending handler returns (or throws), it will pick the oldest request +from this queue and invokes the next handler (and its streaming body will be +resumed).

+

The following example shows how this middleware can be used to ensure no more +than 10 handlers will be invoked at once:

+
$server = new Server(array(
+    new LimitConcurrentRequestsMiddleware(10),
+    $handler
+));
+

Similarly, this middleware is often used in combination with the +RequestBodyBufferMiddleware (see below) +to limit the total number of requests that can be buffered at once:

+
$server = new StreamingServer(array(
+    new LimitConcurrentRequestsMiddleware(100), // 100 concurrent buffering handlers
+    new RequestBodyBufferMiddleware(2 * 1024 * 1024), // 2 MiB per request
+    new RequestBodyParserMiddleware(),
+    $handler
+));
+

More sophisticated examples include limiting the total number of requests +that can be buffered at once and then ensure the actual request handler only +processes one request after another without any concurrency:

+
$server = new StreamingServer(array(
+    new LimitConcurrentRequestsMiddleware(100), // 100 concurrent buffering handlers
+    new RequestBodyBufferMiddleware(2 * 1024 * 1024), // 2 MiB per request
+    new RequestBodyParserMiddleware(),
+    new LimitConcurrentRequestsMiddleware(1), // only execute 1 handler (no concurrency)
+    $handler
+));
+

+RequestBodyBufferMiddleware

+

One of the built-in middleware is the RequestBodyBufferMiddleware which +can be used to buffer the whole incoming request body in memory. +This can be useful if full PSR-7 compatibility is needed for the request handler +and the default streaming request body handling is not needed. +The constructor accepts one optional argument, the maximum request body size. +When one isn't provided it will use post_max_size (default 8 MiB) from PHP's +configuration. +(Note that the value from your matching SAPI will be used, which is the CLI +configuration in most cases.)

+

Any incoming request that has a request body that exceeds this limit will be +accepted, but its request body will be discarded (empty request body). +This is done in order to avoid having to keep an incoming request with an +excessive size (for example, think of a 2 GB file upload) in memory. +This allows the next middleware handler to still handle this request, but it +will see an empty request body. +This is similar to PHP's default behavior, where the body will not be parsed +if this limit is exceeded. However, unlike PHP's default behavior, the raw +request body is not available via php://input.

+

The RequestBodyBufferMiddleware will buffer requests with bodies of known size +(i.e. with Content-Length header specified) as well as requests with bodies of +unknown size (i.e. with Transfer-Encoding: chunked header).

+

All requests will be buffered in memory until the request body end has +been reached and then call the next middleware handler with the complete, +buffered request. +Similarly, this will immediately invoke the next middleware handler for requests +that have an empty request body (such as a simple GET request) and requests +that are already buffered (such as due to another middleware).

+

Note that the given buffer size limit is applied to each request individually. +This means that if you allow a 2 MiB limit and then receive 1000 concurrent +requests, up to 2000 MiB may be allocated for these buffers alone. +As such, it's highly recommended to use this along with the +LimitConcurrentRequestsMiddleware (see above) to limit +the total number of concurrent requests.

+

Usage:

+
$server = new StreamingServer(array(
+    new LimitConcurrentRequestsMiddleware(100), // 100 concurrent buffering handlers
+    new RequestBodyBufferMiddleware(16 * 1024 * 1024), // 16 MiB
+    function (ServerRequestInterface $request) {
+        // The body from $request->getBody() is now fully available without the need to stream it 
+        return new Response(200);
+    },
+));
+

+RequestBodyParserMiddleware

+

The RequestBodyParserMiddleware takes a fully buffered request body +(generally from RequestBodyBufferMiddleware), +and parses the form values and file uploads from the incoming HTTP request body.

+

This middleware handler takes care of applying values from HTTP +requests that use Content-Type: application/x-www-form-urlencoded or +Content-Type: multipart/form-data to resemble PHP's default superglobals +$_POST and $_FILES. +Instead of relying on these superglobals, you can use the +$request->getParsedBody() and $request->getUploadedFiles() methods +as defined by PSR-7.

+

Accordingly, each file upload will be represented as instance implementing UploadedFileInterface. +Due to its blocking nature, the moveTo() method is not available and throws +a RuntimeException instead. +You can use $contents = (string)$file->getStream(); to access the file +contents and persist this to your favorite data store.

+
$handler = function (ServerRequestInterface $request) {
+    // If any, parsed form fields are now available from $request->getParsedBody()
+    $body = $request->getParsedBody();
+    $name = isset($body['name']) ? $body['name'] : 'unnamed';
+
+    $files = $request->getUploadedFiles();
+    $avatar = isset($files['avatar']) ? $files['avatar'] : null;
+    if ($avatar instanceof UploadedFileInterface) {
+        if ($avatar->getError() === UPLOAD_ERR_OK) {
+            $uploaded = $avatar->getSize() . ' bytes';
+        } elseif ($avatar->getError() === UPLOAD_ERR_INI_SIZE) {
+            $uploaded = 'file too large';
+        } else {
+            $uploaded = 'with error';
+        }
+    } else {
+        $uploaded = 'nothing';
+    }
+
+    return new Response(
+        200,
+        array(
+            'Content-Type' => 'text/plain'
+        ),
+        $name . ' uploaded ' . $uploaded
+    );
+};
+
+$server = new StreamingServer(array((
+    new LimitConcurrentRequestsMiddleware(100), // 100 concurrent buffering handlers
+    new RequestBodyBufferMiddleware(16 * 1024 * 1024), // 16 MiB
+    new RequestBodyParserMiddleware(),
+    $handler
+));
+

See also example #12 for more details.

+

By default, this middleware respects the +upload_max_filesize +(default 2M) ini setting. +Files that exceed this limit will be rejected with an UPLOAD_ERR_INI_SIZE error. +You can control the maximum filesize for each individual file upload by +explicitly passing the maximum filesize in bytes as the first parameter to the +constructor like this:

+
new RequestBodyParserMiddleware(8 * 1024 * 1024); // 8 MiB limit per file
+

By default, this middleware respects the +file_uploads +(default 1) and +max_file_uploads +(default 20) ini settings. +These settings control if any and how many files can be uploaded in a single request. +If you upload more files in a single request, additional files will be ignored +and the getUploadedFiles() method returns a truncated array. +Note that upload fields left blank on submission do not count towards this limit. +You can control the maximum number of file uploads per request by explicitly +passing the second parameter to the constructor like this:

+
new RequestBodyParserMiddleware(10 * 1024, 100); // 100 files with 10 KiB each
+
+

Note that this middleware handler simply parses everything that is already +buffered in the request body. +It is imperative that the request body is buffered by a prior middleware +handler as given in the example above. +This previous middleware handler is also responsible for rejecting incoming +requests that exceed allowed message sizes (such as big file uploads). +The RequestBodyBufferMiddleware used above +simply discards excessive request bodies, resulting in an empty body. +If you use this middleware without buffering first, it will try to parse an +empty (streaming) body and may thus assume an empty data structure. +See also RequestBodyBufferMiddleware for +more details.

+
+
+

PHP's MAX_FILE_SIZE hidden field is respected by this middleware. +Files that exceed this limit will be rejected with an UPLOAD_ERR_FORM_SIZE error.

+
+
+

This middleware respects the +max_input_vars +(default 1000) and +max_input_nesting_level +(default 64) ini settings.

+
+
+

Note that this middleware ignores the +enable_post_data_reading +(default 1) ini setting because it makes little sense to respect here and +is left up to higher-level implementations. +If you want to respect this setting, you have to check its value and +effectively avoid using this middleware entirely.

+
+

+Third-Party Middleware

+

While this project does provide the means to use middleware implementations +(see above), it does not aim to define how middleware implementations should +look like. We realize that there's a vivid ecosystem of middleware +implementations and ongoing effort to standardize interfaces between these with +PSR-15 (HTTP Server Request Handlers) +and support this goal. +As such, this project only bundles a few middleware implementations that are +required to match PHP's request behavior (see above) and otherwise actively +encourages third-party middleware implementations.

+

While we would love to support PSR-15 directy in react/http, we understand +that this interface does not specifically target async APIs and as such does +not take advantage of promises for deferred responses. +The gist of this is that where PSR-15 enforces a ResponseInterface return +value, we also accept a PromiseInterface<ResponseInterface>. +As such, we suggest using the external +PSR-15 middleware adapter +that uses on the fly monkey patching of these return values which makes using +most PSR-15 middleware possible with this package without any changes required.

+

Other than that, you can also use the above middleware definition +to create custom middleware. A non-exhaustive list of third-party middleware can +be found at the middleware wiki. +If you build or know a custom middleware, make sure to let the world know and +feel free to add it to this list.

+

+Install

+

The recommended way to install this library is through Composer. +New to Composer?

+

This will install the latest supported version:

+
$ composer require react/http:^0.8.3
+

See also the CHANGELOG for details about version upgrades.

+

This project aims to run on any platform and thus does not require any PHP +extensions and supports running on legacy PHP 5.3 through current PHP 7+ and +HHVM. +It's highly recommended to use PHP 7+ for this project.

+

+Tests

+

To run the test suite, you first need to clone this repo and then install all +dependencies through Composer:

+
$ composer install
+

To run the test suite, go to the project root and run:

+
$ php vendor/bin/phpunit
+

+License

+

MIT, see LICENSE file.

+
+ +
+
+
+ + + + + + diff --git a/http/license.html b/http/license.html new file mode 100644 index 000000000..d92c9fc3c --- /dev/null +++ b/http/license.html @@ -0,0 +1,552 @@ + + + + + + + + HTTP: License - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

HTTP License

+ +

Copyright (c) 2012 Igor Wiedler, Chris Boden

+

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions:

+

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.

+
+ +
+
+
+ + + + + + diff --git a/index.html b/index.html new file mode 100644 index 000000000..7b55cc6cd --- /dev/null +++ b/index.html @@ -0,0 +1,648 @@ + + + + + + + + Event-driven, non-blocking I/O with PHP - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+
+ +
+

+Event-driven, non-blocking I/O with PHP

+

ReactPHP is a low-level library for event-driven programming in +PHP. At its core is an event loop, on +top of which it provides low-level utilities, such as: Streams +abstraction, async dns resolver, network client/server, http +client/server, interaction with processes. Third-party libraries can +use these components to create async network clients/servers and +more.

+ + + +
+
+
+
+
+ +
+
+
+
$loop = React\EventLoop\Factory::create();
+
+$server = new React\Http\Server(function (Psr\Http\Message\ServerRequestInterface $request) {
+    return new React\Http\Response(
+        200,
+        array('Content-Type' => 'text/plain'),
+        "Hello World!\n"
+    );
+});
+
+$socket = new React\Socket\Server(8080, $loop);
+$server->listen($socket);
+
+echo "Server running at http://127.0.0.1:8080\n";
+
+$loop->run();
+

This simple web server written in ReactPHP responds with "Hello World" for every request.

+
+
+
+
+ +
+ +
+
+
+ +
+
+
+ +
+ + + + + + +
+ + + +
+ + + +
+ +
+
+

+ + Talks +

+ +
+
+
+
+ +
+
+ + youtube.com + +
+
+
+
+ +
+
+ + youtube.com + +
+
+
+
+ +
+
+ + youtube.com + +
+
+
+
+ + + + + + diff --git a/manifest.json b/manifest.json new file mode 100644 index 000000000..4a8175465 --- /dev/null +++ b/manifest.json @@ -0,0 +1,18 @@ +{ + "name": "ReactPHP", + "icons": [ + { + "src": "android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#f4f3f1", + "background_color": "#f4f3f1", + "display": "standalone" +} \ No newline at end of file diff --git a/mstile-150x150.png b/mstile-150x150.png new file mode 100644 index 0000000000000000000000000000000000000000..66faa94f4c6ad7f81fbfe91865b606b7c50c321e GIT binary patch literal 3973 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∋wP@-?KG4`zyTm|G7BR&cv%CVen50u7Vo>` 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 + + + + + + + PromiseStream: Changelog - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

PromiseStream Changelog

+ + + +

+ + 2017 +

+ + +

+ + + 1.1.1 + + + (2017-12-22) + + Release on GitHub + + +

+ +
    +
  • +

    Fix: Fix all() to assume null values if no event data is passed
    +(#13 by @clue)

    +
  • +
  • +

    Improve test suite by simplifying test bootstrapping logic via Composer and
    +add forward compatibility with PHPUnit 5 and PHPUnit 6 and
    +test against PHP 7.1 and 7.2
    +(#11 and #12 by @clue and #9 by @carusogabriel)

    +
  • +
+ +
+ +

+ + + 1.1.0 + + + (2017-11-28) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Reject first() when stream emits an error event
    +(#7 by @clue)

    +
  • +
  • +

    Fix: Explicit close() of unwrapped stream should not emit error event
    +(#8 by @clue)

    +
  • +
  • +

    Internal refactoring to simplify buffer() function
    +(#6 by @kelunik)

    +
  • +
+ +
+ +

+ + + 1.0.0 + + + (2017-10-24) + + Release on GitHub + + +

+ +
    +
  • First stable release, now following SemVer
  • +
+
+

Contains no other changes, so it's actually fully compatible with the v0.1.2 release.

+
+ +
+ +

+ + + 0.1.2 + + + (2017-10-18) + + Release on GitHub + + +

+ +
    +
  • Feature: Optional maximum buffer length for buffer() (#3 by @WyriHaximus)
  • +
  • Improvement: Readme improvements (#5 by @jsor)
  • +
+ +
+ +

+ + + 0.1.1 + + + (2017-05-15) + + Release on GitHub + + +

+ +
    +
  • Improvement: Forward compatibility with stream 1.0, 0.7, 0.6, and 0.5 (#2 by @WyriHaximus)
  • +
+ +
+ +

+ + + 0.1.0 + + + (2017-05-10) + + Release on GitHub + + +

+ + + +
+
+ +
+
+
+ + + + + + diff --git a/promise-stream/index.html b/promise-stream/index.html new file mode 100644 index 000000000..1c2ea5801 --- /dev/null +++ b/promise-stream/index.html @@ -0,0 +1,553 @@ + + + + + + + + PromiseStream: +PromiseStream - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

PromiseStream

+ + +

Build Status

+

The missing link between Promise-land and Stream-land +for ReactPHP.

+

Table of Contents

+ +

+Usage

+

This lightweight library consists only of a few simple functions. +All functions reside under the React\Promise\Stream namespace.

+

The below examples assume you use an import statement similar to this:

+
use React\Promise\Stream;
+
+Stream\buffer(…);
+

Alternatively, you can also refer to them with their fully-qualified name:

+
\React\Promise\Stream\buffer(…);
+

+buffer()

+

The buffer(ReadableStreamInterface $stream, int $maxLength = null) function can be used to create +a Promise which resolves with the stream data buffer. With an optional maximum length argument +which defaults to no limit. In case the maximum length is reached before the end the promise will +be rejected with a \OverflowException.

+
$stream = accessSomeJsonStream();
+
+Stream\buffer($stream)->then(function ($contents) {
+    var_dump(json_decode($contents));
+});
+

The promise will resolve with all data chunks concatenated once the stream closes.

+

The promise will resolve with an empty string if the stream is already closed.

+

The promise will reject if the stream emits an error.

+

The promise will reject if it is canceled.

+
$stream = accessSomeToLargeStream();
+
+Stream\buffer($stream, 1024)->then(function ($contents) {
+    var_dump(json_decode($contents));
+}, function ($error) {
+    // Reaching here when the stream buffer goes above the max size,
+    // in this example that is 1024 bytes,
+    // or when the stream emits an error. 
+});
+

+first()

+

The first(ReadableStreamInterface|WritableStreamInterface $stream, $event = 'data') +function can be used to create a Promise which resolves once the given event triggers for the first time.

+
$stream = accessSomeJsonStream();
+
+Stream\first($stream)->then(function ($chunk) {
+    echo 'The first chunk arrived: ' . $chunk;
+});
+

The promise will resolve with whatever the first event emitted or null if the +event does not pass any data. +If you do not pass a custom event name, then it will wait for the first "data" +event and resolve with a string containing the first data chunk.

+

The promise will reject if the stream emits an error – unless you're waiting for +the "error" event, in which case it will resolve.

+

The promise will reject once the stream closes – unless you're waiting for the +"close" event, in which case it will resolve.

+

The promise will reject if the stream is already closed.

+

The promise will reject if it is canceled.

+

+all()

+

The all(ReadableStreamInterface|WritableStreamInterface $stream, $event = 'data') +function can be used to create a Promise which resolves with an array of all the event data.

+
$stream = accessSomeJsonStream();
+
+Stream\all($stream)->then(function ($chunks) {
+    echo 'The stream consists of ' . count($chunks) . ' chunk(s)';
+});
+

The promise will resolve with an array of whatever all events emitted or null if the +events do not pass any data. +If you do not pass a custom event name, then it will wait for all the "data" +events and resolve with an array containing all the data chunks.

+

The promise will resolve with an array once the stream closes.

+

The promise will resolve with an empty array if the stream is already closed.

+

The promise will reject if the stream emits an error.

+

The promise will reject if it is canceled.

+

+unwrapReadable()

+

The unwrapReadable(PromiseInterface $promise) function can be used to unwrap +a Promise which resolves with a ReadableStreamInterface.

+

This function returns a readable stream instance (implementing ReadableStreamInterface) +right away which acts as a proxy for the future promise resolution. +Once the given Promise resolves with a ReadableStreamInterface, its data will +be piped to the output stream.

+
//$promise = someFunctionWhichResolvesWithAStream();
+$promise = startDownloadStream($uri);
+
+$stream = Stream\unwrapReadable($promise);
+
+$stream->on('data', function ($data) {
+   echo $data;
+});
+
+$stream->on('end', function () {
+   echo 'DONE';
+});
+

If the given promise is either rejected or fulfilled with anything but an +instance of ReadableStreamInterface, then the output stream will emit +an error event and close:

+
$promise = startDownloadStream($invalidUri);
+
+$stream = Stream\unwrapReadable($promise);
+
+$stream->on('error', function (Exception $error) {
+    echo 'Error: ' . $error->getMessage();
+});
+

The given $promise SHOULD be pending, i.e. it SHOULD NOT be fulfilled or rejected +at the time of invoking this function. +If the given promise is already settled and does not resolve with an +instance of ReadableStreamInterface, then you will not be able to receive +the error event.

+

You can close() the resulting stream at any time, which will either try to +cancel() the pending promise or try to close() the underlying stream.

+
$promise = startDownloadStream($uri);
+
+$stream = Stream\unwrapReadable($promise);
+
+$loop->addTimer(2.0, function () use ($stream) {
+    $stream->close();
+});
+

+unwrapWritable()

+

The unwrapWritable(PromiseInterface $promise) function can be used to unwrap +a Promise which resolves with a WritableStreamInterface.

+

This function returns a writable stream instance (implementing WritableStreamInterface) +right away which acts as a proxy for the future promise resolution. +Once the given Promise resolves with a WritableStreamInterface, any data you +wrote to the proxy will be piped to the inner stream.

+
//$promise = someFunctionWhichResolvesWithAStream();
+$promise = startUploadStream($uri);
+
+$stream = Stream\unwrapWritable($promise);
+
+$stream->write('hello');
+$stream->end('world');
+
+$stream->on('close', function () {
+   echo 'DONE';
+});
+

If the given promise is either rejected or fulfilled with anything but an +instance of WritableStreamInterface, then the output stream will emit +an error event and close:

+
$promise = startUploadStream($invalidUri);
+
+$stream = Stream\unwrapWritable($promise);
+
+$stream->on('error', function (Exception $error) {
+    echo 'Error: ' . $error->getMessage();
+});
+

The given $promise SHOULD be pending, i.e. it SHOULD NOT be fulfilled or rejected +at the time of invoking this function. +If the given promise is already settled and does not resolve with an +instance of WritableStreamInterface, then you will not be able to receive +the error event.

+

You can close() the resulting stream at any time, which will either try to +cancel() the pending promise or try to close() the underlying stream.

+
$promise = startUploadStream($uri);
+
+$stream = Stream\unwrapWritable($promise);
+
+$loop->addTimer(2.0, function () use ($stream) {
+    $stream->close();
+});
+

+Install

+

The recommended way to install this library is through Composer. +New to Composer?

+

This project follows SemVer. +This will install the latest supported version:

+
$ composer require react/promise-stream:^1.1.1
+

See also the CHANGELOG for details about version upgrades.

+

This project aims to run on any platform and thus does not require any PHP +extensions and supports running on legacy PHP 5.3 through current PHP 7+ and +HHVM. +It's highly recommended to use PHP 7+ for this project.

+

+License

+

MIT, see LICENSE file.

+
+ +
+
+
+ + + + + + diff --git a/promise-stream/license.html b/promise-stream/license.html new file mode 100644 index 000000000..596f6ead3 --- /dev/null +++ b/promise-stream/license.html @@ -0,0 +1,378 @@ + + + + + + + + PromiseStream: License - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

PromiseStream License

+ +

The MIT License (MIT)

+

Copyright (c) 2016 Christian Lück

+

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions:

+

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.

+
+ +
+
+
+ + + + + + diff --git a/promise-timer/changelog.html b/promise-timer/changelog.html new file mode 100644 index 000000000..7acdcdbba --- /dev/null +++ b/promise-timer/changelog.html @@ -0,0 +1,575 @@ + + + + + + + + PromiseTimer: Changelog - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

PromiseTimer Changelog

+ + + +

+ + 2018 +

+ + +

+ + + 1.5.0 + + + (2018-06-13) + + Release on GitHub + + +

+ +
    +
  • Feature: Improve memory consumption by cleaning up garbage references to pending promise without canceller.
    +(#34 by @clue)
  • +
+ +
+ +

+ + + 1.4.0 + + + (2018-06-11) + + Release on GitHub + + +

+ +
    +
  • Feature: Improve memory consumption by cleaning up garbage references.
    +(#33 by @clue)
  • +
+ +
+ +

+ + + 1.3.0 + + + (2018-04-24) + + Release on GitHub + + +

+ +
    +
  • Feature: Improve memory consumption by cleaning up unneeded references.
    +(#32 by @clue)
  • +
+ +
+

+ + 2017 +

+ + +

+ + + 1.2.1 + + + (2017-12-22) + + Release on GitHub + + +

+ +
    +
  • +

    README improvements
    +(#28 by @jsor)

    +
  • +
  • +

    Improve test suite by adding forward compatiblity with PHPUnit 6 and
    +fix test suite forward compatibility with upcoming EventLoop releases
    +(#30 and #31 by @clue)

    +
  • +
+ +
+ +

+ + + 1.2.0 + + + (2017-08-08) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Only start timers if input Promise is still pending and
    +return a settled output promise if the input is already settled.
    +(#25 by @clue)

    +
  • +
  • +

    Feature: Cap minimum timer interval at 1µs across all versions
    +(#23 by @clue)

    +
  • +
  • +

    Feature: Forward compatibility with EventLoop v1.0 and v0.5
    +(#27 by @clue)

    +
  • +
  • +

    Improve test suite by adding PHPUnit to require-dev and
    +lock Travis distro so new defaults will not break the build
    +(#24 and #26 by @clue)

    +
  • +
+ +
+

+ + 2016 +

+ + +

+ + + 1.1.1 + + + (2016-12-27) + + Release on GitHub + + +

+ +
    +
  • Improve test suite to use PSR-4 autoloader and proper namespaces.
    +(#21 by @clue)
  • +
+ +
+ +

+ + + 1.1.0 + + + (2016-02-29) + + Release on GitHub + + +

+ +
    +
  • Feature: Support promise cancellation for all timer primitives
    +(#18 by @clue)
  • +
+ +
+

+ + 2015 +

+ + +

+ + + 1.0.0 + + + (2015-09-29) + + Release on GitHub + + +

+ +
    +
  • First tagged release
  • +
+ +
+
+ +
+
+
+ + + + + + diff --git a/promise-timer/index.html b/promise-timer/index.html new file mode 100644 index 000000000..bf0086824 --- /dev/null +++ b/promise-timer/index.html @@ -0,0 +1,661 @@ + + + + + + + + PromiseTimer: +PromiseTimer - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

PromiseTimer

+ + +

Build Status

+

A trivial implementation of timeouts for Promises, built on top of ReactPHP.

+

Table of contents

+ +

+Usage

+

This lightweight library consists only of a few simple functions. +All functions reside under the React\Promise\Timer namespace.

+

The below examples assume you use an import statement similar to this:

+
use React\Promise\Timer;
+
+Timer\timeout(…);
+

Alternatively, you can also refer to them with their fully-qualified name:

+
\React\Promise\Timer\timeout(…);
+

+timeout()

+

The timeout(PromiseInterface $promise, $time, LoopInterface $loop) function +can be used to cancel operations that take too long. +You need to pass in an input $promise that represents a pending operation and timeout parameters. +It returns a new Promise with the following resolution behavior:

+
    +
  • If the input $promise resolves before $time seconds, resolve the resulting promise with its fulfillment value.
  • +
  • If the input $promise rejects before $time seconds, reject the resulting promise with its rejection value.
  • +
  • If the input $promise does not settle before $time seconds, cancel the operation and reject the resulting promise with a TimeoutException.
  • +
+

Internally, the given $time value will be used to start a timer that will +cancel the pending operation once it triggers. +This implies that if you pass a really small (or negative) value, it will still +start a timer and will thus trigger at the earliest possible time in the future.

+

If the input $promise is already settled, then the resulting promise will +resolve or reject immediately without starting a timer at all.

+

A common use case for handling only resolved values looks like this:

+
$promise = accessSomeRemoteResource();
+Timer\timeout($promise, 10.0, $loop)->then(function ($value) {
+    // the operation finished within 10.0 seconds
+});
+

A more complete example could look like this:

+
$promise = accessSomeRemoteResource();
+Timer\timeout($promise, 10.0, $loop)->then(
+    function ($value) {
+        // the operation finished within 10.0 seconds
+    },
+    function ($error) {
+        if ($error instanceof Timer\TimeoutException) {
+            // the operation has failed due to a timeout
+        } else {
+            // the input operation has failed due to some other error
+        }
+    }
+);
+

Or if you're using react/promise v2.2.0 or up:

+
Timer\timeout($promise, 10.0, $loop)
+    ->then(function ($value) {
+        // the operation finished within 10.0 seconds
+    })
+    ->otherwise(function (Timer\TimeoutException $error) {
+        // the operation has failed due to a timeout
+    })
+    ->otherwise(function ($error) {
+        // the input operation has failed due to some other error
+    })
+;
+

+Timeout cancellation

+

As discussed above, the timeout() function will cancel the +underlying operation if it takes too long. +This means that you can be sure the resulting promise will then be rejected +with a TimeoutException.

+

However, what happens to the underlying input $promise is a bit more tricky: +Once the timer fires, we will try to call +$promise->cancel() +on the input $promise which in turn invokes its cancellation handler.

+

This means that it's actually up the input $promise to handle +cancellation support.

+
    +
  • +

    A common use case involves cleaning up any resources like open network sockets or +file handles or terminating external processes or timers.

    +
  • +
  • +

    If the given input $promise does not support cancellation, then this is a NO-OP. +This means that while the resulting promise will still be rejected, the underlying +input $promise may still be pending and can hence continue consuming resources.

    +
  • +
+

See the following chapter for more details on the cancellation handler.

+

+Cancellation handler

+

For example, an implementation for the above operation could look like this:

+
function accessSomeRemoteResource()
+{
+    return new Promise(
+        function ($resolve, $reject) use (&$socket) {
+            // this will be called once the promise is created
+            // a common use case involves opening any resources and eventually resolving
+            $socket = createSocket();
+            $socket->on('data', function ($data) use ($resolve) {
+                $resolve($data);
+            });
+        },
+        function ($resolve, $reject) use (&$socket) {
+            // this will be called once calling `cancel()` on this promise
+            // a common use case involves cleaning any resources and then rejecting
+            $socket->close();
+            $reject(new \RuntimeException('Operation cancelled'));
+        }
+    );
+}
+

In this example, calling $promise->cancel() will invoke the registered cancellation +handler which then closes the network socket and rejects the Promise instance.

+

If no cancellation handler is passed to the Promise constructor, then invoking +its cancel() method it is effectively a NO-OP. +This means that it may still be pending and can hence continue consuming resources.

+

For more details on the promise cancellation, please refer to the +Promise documentation.

+

+Input cancellation

+

Irrespective of the timout handling, you can also explicitly cancel() the +input $promise at any time. +This means that the timeout() handling does not affect cancellation of the +input $promise, as demonstrated in the following example:

+
$promise = accessSomeRemoteResource();
+$timeout = Timer\timeout($promise, 10.0, $loop);
+
+$promise->cancel();
+

The registered cancellation handler is responsible for +handling the cancel() call:

+
    +
  • A described above, a common use involves resource cleanup and will then reject +the Promise. +If the input $promise is being rejected, then the timeout will be aborted +and the resulting promise will also be rejected.
  • +
  • If the input $promise is still pending, then the timout will continue +running until the timer expires. +The same happens if the input $promise does not register a +cancellation handler.
  • +
+

+Output cancellation

+

Similarily, you can also explicitly cancel() the resulting promise like this:

+
$promise = accessSomeRemoteResource();
+$timeout = Timer\timeout($promise, 10.0, $loop);
+
+$timeout->cancel();
+

Note how this looks very similar to the above input cancellation +example. Accordingly, it also behaves very similar.

+

Calling cancel() on the resulting promise will merely try +to cancel() the input $promise. +This means that we do not take over responsibility of the outcome and it's +entirely up to the input $promise to handle cancellation support.

+

The registered cancellation handler is responsible for +handling the cancel() call:

+
    +
  • As described above, a common use involves resource cleanup and will then reject +the Promise. +If the input $promise is being rejected, then the timeout will be aborted +and the resulting promise will also be rejected.
  • +
  • If the input $promise is still pending, then the timout will continue +running until the timer expires. +The same happens if the input $promise does not register a +cancellation handler.
  • +
+

To re-iterate, note that calling cancel() on the resulting promise will merely +try to cancel the input $promise only. +It is then up to the cancellation handler of the input promise to settle the promise. +If the input promise is still pending when the timeout occurs, then the normal +timeout cancellation handling will trigger, effectively rejecting +the output promise with a TimeoutException.

+

This is done for consistency with the timeout cancellation +handling and also because it is assumed this is often used like this:

+
$timeout = Timer\timeout(accessSomeRemoteResource(), 10.0, $loop);
+
+$timeout->cancel();
+

As described above, this example works as expected and cleans up any resources +allocated for the input $promise.

+

Note that if the given input $promise does not support cancellation, then this +is a NO-OP. +This means that while the resulting promise will still be rejected after the +timeout, the underlying input $promise may still be pending and can hence +continue consuming resources.

+

+Collections

+

If you want to wait for multiple promises to resolve, you can use the normal promise primitives like this:

+
$promises = array(
+    accessSomeRemoteResource(),
+    accessSomeRemoteResource(),
+    accessSomeRemoteResource()
+);
+
+$promise = \React\Promise\all($promises);
+
+Timer\timeout($promise, 10, $loop)->then(function ($values) {
+    // *all* promises resolved
+});
+

The applies to all promise collection primitives alike, i.e. all(), race(), any(), some() etc.

+

For more details on the promise primitives, please refer to the +Promise documentation.

+

+resolve()

+

The resolve($time, LoopInterface $loop) function can be used to create a new Promise that +resolves in $time seconds with the $time as the fulfillment value.

+
Timer\resolve(1.5, $loop)->then(function ($time) {
+    echo 'Thanks for waiting ' . $time . ' seconds' . PHP_EOL;
+});
+

Internally, the given $time value will be used to start a timer that will +resolve the promise once it triggers. +This implies that if you pass a really small (or negative) value, it will still +start a timer and will thus trigger at the earliest possible time in the future.

+

+Resolve cancellation

+

You can explicitly cancel() the resulting timer promise at any time:

+
$timer = Timer\resolve(2.0, $loop);
+
+$timer->cancel();
+

This will abort the timer and reject with a RuntimeException.

+

+reject()

+

The reject($time, LoopInterface $loop) function can be used to create a new Promise +which rejects in $time seconds with a TimeoutException.

+
Timer\reject(2.0, $loop)->then(null, function (TimeoutException $e) {
+    echo 'Rejected after ' . $e->getTimeout() . ' seconds ' . PHP_EOL;
+});
+

Internally, the given $time value will be used to start a timer that will +reject the promise once it triggers. +This implies that if you pass a really small (or negative) value, it will still +start a timer and will thus trigger at the earliest possible time in the future.

+

This function complements the resolve() function +and can be used as a basic building block for higher-level promise consumers.

+

+Reject cancellation

+

You can explicitly cancel() the resulting timer promise at any time:

+
$timer = Timer\reject(2.0, $loop);
+
+$timer->cancel();
+

This will abort the timer and reject with a RuntimeException.

+

+TimeoutException

+

The TimeoutException extends PHP's built-in RuntimeException.

+

The getTimeout() method can be used to get the timeout value in seconds.

+

+Install

+

The recommended way to install this library is through Composer. +New to Composer?

+

This project follows SemVer. +This will install the latest supported version:

+
$ composer require react/promise-timer:^1.5
+

See also the CHANGELOG for details about version upgrades.

+

This project aims to run on any platform and thus does not require any PHP +extensions and supports running on legacy PHP 5.3 through current PHP 7+ and +HHVM. +It's highly recommended to use PHP 7+ for this project.

+

+Tests

+

To run the test suite, you first need to clone this repo and then install all +dependencies through Composer:

+
$ composer install
+

To run the test suite, go to the project root and run:

+
$ php vendor/bin/phpunit
+

+License

+

MIT, see LICENSE file.

+
+ +
+
+
+ + + + + + diff --git a/promise-timer/license.html b/promise-timer/license.html new file mode 100644 index 000000000..e1dc1e049 --- /dev/null +++ b/promise-timer/license.html @@ -0,0 +1,383 @@ + + + + + + + + PromiseTimer: License - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

PromiseTimer License

+ +

The MIT License (MIT)

+

Copyright (c) 2015 Christian Lück

+

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions:

+

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.

+
+ +
+
+
+ + + + + + diff --git a/promise/changelog.html b/promise/changelog.html new file mode 100644 index 000000000..1b8d9ed4d --- /dev/null +++ b/promise/changelog.html @@ -0,0 +1,946 @@ + + + + + + + + Promise: Changelog - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

Promise Changelog

+ + + +

+ + 2018 +

+ + +

+ + + 2.7.0 + + + (2018-06-13) + + Release on GitHub + + +

+ +
    +
  • Feature: Improve memory consumption for pending promises by using static internal callbacks without binding to self.
    +(#124 by @clue)
  • +
+ +
+ +

+ + + 2.6.0 + + + (2018-06-11) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Significantly improve memory consumption and performance by only passing resolver args
    +to resolver and canceller if callback requires them. Also use static callbacks without
    +binding to promise, clean up canceller function reference when they are no longer
    +needed and hide resolver and canceller references from call stack on PHP 7+.
    +(#113, #115, #116, #117, #118, #119 and #123 by @clue)

    +

    These changes combined mean that rejecting promises with an Exception should
    +no longer cause any internal circular references which could cause some unexpected
    +memory growth in previous versions. By explicitly avoiding and explicitly
    +cleaning up said references, we can avoid relying on PHP's circular garbage collector
    +to kick in which significantly improves performance when rejecting many promises.

    +
  • +
  • +

    Mark legacy progress support / notification API as deprecated
    +(#112 by @clue)

    +
  • +
  • +

    Recommend rejecting promises by throwing an exception
    +(#114 by @jsor)

    +
  • +
  • +

    Improve documentation to properly instantiate LazyPromise
    +(#121 by @holtkamp)

    +
  • +
  • +

    Follower cancellation propagation was originally planned for this release
    +but has been reverted for now and is planned for a future release.
    +(#99 by @jsor and #122 by @clue)

    +
  • +
+ +
+

+ + 2017 +

+ + +

+ + + 2.5.1 + + + (2017-03-25) + + Release on GitHub + + +

+ +
    +
  • Fix circular references when resolving with a promise which follows itself (#94).
  • +
+ +
+

+ + 2016 +

+ + +

+ + + 2.5.0 + + + (2016-12-22) + + Release on GitHub + + +

+ +
    +
  • +

    Revert automatic cancellation of pending collection promises once the output promise resolves. This was introduced in 42d86b7 (PR #36, released in v2.3.0) and was both unintended and backward incompatible.

    +

    If you need automatic cancellation, you can use something like:

    +
    function allAndCancel(array $promises)
    +{
    +     return \React\Promise\all($promises)
    +         ->always(function() use ($promises) {
    +             foreach ($promises as $promise) {
    +                 if ($promise instanceof \React\Promise\CancellablePromiseInterface) {
    +                     $promise->cancel();
    +                 }
    +             }
    +        });
    +}
    +
  • +
  • +

    all() and map() functions now preserve the order of the array (#77).

    +
  • +
  • +

    Fix circular references when resolving a promise with itself (#71).

    +
  • +
+ +
+ +

+ + + 2.4.1 + + + (2016-05-03) + + Release on GitHub + + +

+ +
    +
  • Fix some() not cancelling pending promises when too much input promises reject (16ff799).
  • +
+ +
+ +

+ + + 2.4.0 + + + (2016-03-31) + + Release on GitHub + + +

+ +
    +
  • Support foreign thenables in resolve().
    +Any object that provides a then() method is now assimilated to a trusted promise that follows the state of this thenable (#52).
  • +
  • Fix some() and any() for input arrays containing not enough items (#34).
  • +
+ +
+ +

+ + + 2.3.0 + + + (2016-03-24) + + Release on GitHub + + +

+ +
    +
  • Allow cancellation of promises returned by functions working on promise collections (#36).
  • +
  • Handle \Throwable in the same way as \Exception (#51 by @joshdifabio).
  • +
+ +
+ +

+ + + 1.2.1 + + + (2016-03-07) + + Release on GitHub + + +

+ +
    +
  • Fix DeferredPromise to also implement the CancellablePromiseInterface.
  • +
+ +
+ +

+ + + 1.2.0 + + + (2016-02-27) + + Release on GitHub + + +

+ +

This release makes the API more compatible with 2.0 while preserving full backward compatibility.

+
    +
  • Introduce new CancellablePromiseInterface implemented by all promises.
  • +
  • Add new .cancel() method (part of the CancellablePromiseInterface).
  • +
+ +
+ +

+ + + 2.2.2 + + + (2016-02-26) + + Release on GitHub + + +

+ +
    +
  • Fix cancellation handlers called multiple times (#47 by @clue).
  • +
+ +
+

+ + 2015 +

+ + +

+ + + 2.2.1 + + + (2015-07-03) + + Release on GitHub + + +

+ +
    +
  • Fix stack error when resolving a promise in its own fulfillment or rejection handlers.
  • +
+ +
+ +

+ + + 1.1.0 + + + (2015-07-01) + + Release on GitHub + + +

+ +

This release makes the API more compatible with 2.0 while preserving full backward compatibility.

+
    +
  • Add React\Promise\Promise class.
  • +
  • Move methods of React\Promise\When and React\Promise\Util to functions while keeping the classes as a proxy for BC.
  • +
+ +
+

+ + 2014 +

+ + +

+ + + 2.2.0 + + + (2014-12-30) + + Release on GitHub + + +

+ +

This release introduces the ExtendedPromiseInterface.

+

The ExtendedPromiseInterface extends the PromiseInterface with useful shortcut
+and utility methods which are not part of the Promises/A specification.

+ +
+ +

+ + + 2.1.0 + + + (2014-10-15) + + Release on GitHub + + +

+ +

Introduce new CancellablePromiseInterface implemented by all promises.

+ +
+

+ + 2013 +

+ + +

+ + + 2.0.0 + + + (2013-12-10) + + Release on GitHub + + +

+ +

New major release. The goal was to streamline the API and to make it more compliant with other promise libraries and especially with the new upcoming ES6 promises specification.

+
    +
  • Add standalone Promise class.
  • +
  • Add new React\Promise\race() function.
  • +
  • BC break: Bump minimum PHP version to PHP 5.4.
  • +
  • BC break: Remove ResolverInterface and PromiseInterface from Deferred.
  • +
  • BC break: Change signature of PromiseInterface.
  • +
  • BC break: Remove When and Util classes and move static methods to functions.
  • +
  • BC break: FulfilledPromise and RejectedPromise now throw an exception when initialized with a promise instead of a value/reason.
  • +
  • BC break: React\Promise\Deferred::resolve() and React\Promise\Deferred::reject() no longer return a promise.
  • +
+ +
+ +

+ + + 1.0.4 + + + (2013-04-03) + + Release on GitHub + + +

+ +
    +
  • Trigger PHP errors when invalid callback is passed.
  • +
  • Fully resolve rejection value before calling rejection handler.
  • +
  • Add When::lazy() to create lazy promises which will be initialized once a consumer calls the then() method.
  • +
+ +
+

+ + 2012 +

+ + +

+ + + 1.0.3 + + + (2012-11-17) + + Release on GitHub + + +

+ +
    +
  • Add PromisorInterface for objects that have a promise() method.
  • +
+ +
+ +

+ + + 1.0.2 + + + (2012-11-14) + + Release on GitHub + + +

+ +
    +
  • Fix bug in When::any() not correctly unwrapping to a single result value
  • +
  • $promiseOrValue argument of When::resolve() and When::reject() is now optional
  • +
+ +
+ +

+ + + 1.0.1 + + + (2012-11-13) + + Release on GitHub + + +

+ +
    +
  • Prevent deep recursion which was reaching xdebug.max_nesting_level default of 100
  • +
+ +
+ +

+ + + 1.0.0 + + + (2012-11-07) + + Release on GitHub + + +

+ +
    +
  • First tagged release
  • +
+ +
+
+ +
+
+
+ + + + + + diff --git a/promise/index.html b/promise/index.html new file mode 100644 index 000000000..02083dd33 --- /dev/null +++ b/promise/index.html @@ -0,0 +1,1174 @@ + + + + + + + + Promise: +Promise - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

Promise

+ + +

A lightweight implementation of +CommonJS Promises/A for PHP.

+

Build Status +Coverage Status

+

+Table of Contents

+
    +
  1. Introduction
  2. +
  3. +Concepts + +
  4. +
  5. +API + +
  6. +
  7. +Examples + +
  8. +
  9. Install
  10. +
  11. Credits
  12. +
  13. License
  14. +
+

+Introduction

+

Promise is a library implementing +CommonJS Promises/A for PHP.

+

It also provides several other useful promise-related concepts, such as joining +multiple promises and mapping and reducing collections of promises.

+

If you've never heard about promises before, +read this first.

+

+Concepts

+

+Deferred

+

A Deferred represents a computation or unit of work that may not have +completed yet. Typically (but not always), that computation will be something +that executes asynchronously and completes at some point in the future.

+

+Promise

+

While a deferred represents the computation itself, a Promise represents +the result of that computation. Thus, each deferred has a promise that acts as +a placeholder for its actual result.

+

+API

+

+Deferred

+

A deferred represents an operation whose resolution is pending. It has separate +promise and resolver parts.

+
$deferred = new React\Promise\Deferred();
+
+$promise = $deferred->promise();
+
+$deferred->resolve(mixed $value = null);
+$deferred->reject(mixed $reason = null);
+$deferred->notify(mixed $update = null);
+

The promise method returns the promise of the deferred.

+

The resolve and reject methods control the state of the deferred.

+

The deprecated notify method is for progress notification.

+

The constructor of the Deferred accepts an optional $canceller argument. +See Promise for more information.

+

+Deferred::promise()

+
$promise = $deferred->promise();
+

Returns the promise of the deferred, which you can hand out to others while +keeping the authority to modify its state to yourself.

+

+Deferred::resolve()

+
$deferred->resolve(mixed $value = null);
+

Resolves the promise returned by promise(). All consumers are notified by +having $onFulfilled (which they registered via $promise->then()) called with +$value.

+

If $value itself is a promise, the promise will transition to the state of +this promise once it is resolved.

+

+Deferred::reject()

+
$deferred->reject(mixed $reason = null);
+

Rejects the promise returned by promise(), signalling that the deferred's +computation failed. +All consumers are notified by having $onRejected (which they registered via +$promise->then()) called with $reason.

+

If $reason itself is a promise, the promise will be rejected with the outcome +of this promise regardless whether it fulfills or rejects.

+

+Deferred::notify()

+
+

Deprecated in v2.6.0: Progress support is deprecated and should not be used anymore.

+
+
$deferred->notify(mixed $update = null);
+

Triggers progress notifications, to indicate to consumers that the computation +is making progress toward its result.

+

All consumers are notified by having $onProgress (which they registered via +$promise->then()) called with $update.

+

+PromiseInterface

+

The promise interface provides the common interface for all promise +implementations.

+

A promise represents an eventual outcome, which is either fulfillment (success) +and an associated value, or rejection (failure) and an associated reason.

+

Once in the fulfilled or rejected state, a promise becomes immutable. +Neither its state nor its result (or error) can be modified.

+

+Implementations

+ +

+PromiseInterface::then()

+
$transformedPromise = $promise->then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null);
+

Transforms a promise's value by applying a function to the promise's fulfillment +or rejection value. Returns a new promise for the transformed result.

+

The then() method registers new fulfilled, rejection and progress handlers +with a promise (all parameters are optional):

+
    +
  • +$onFulfilled will be invoked once the promise is fulfilled and passed +the result as the first argument.
  • +
  • +$onRejected will be invoked once the promise is rejected and passed the +reason as the first argument.
  • +
  • +$onProgress (deprecated) will be invoked whenever the producer of the promise +triggers progress notifications and passed a single argument (whatever it +wants) to indicate progress.
  • +
+

It returns a new promise that will fulfill with the return value of either +$onFulfilled or $onRejected, whichever is called, or will reject with +the thrown exception if either throws.

+

A promise makes the following guarantees about handlers registered in +the same call to then():

+
    +
  1. Only one of $onFulfilled or $onRejected will be called, +never both.
  2. +
  3. +$onFulfilled and $onRejected will never be called more +than once.
  4. +
  5. +$onProgress (deprecated) may be called multiple times.
  6. +
+

+See also

+ +

+ExtendedPromiseInterface

+

The ExtendedPromiseInterface extends the PromiseInterface with useful shortcut +and utility methods which are not part of the Promises/A specification.

+

+Implementations

+ +

+ExtendedPromiseInterface::done()

+
$promise->done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null);
+

Consumes the promise's ultimate value if the promise fulfills, or handles the +ultimate error.

+

It will cause a fatal error if either $onFulfilled or $onRejected throw or +return a rejected promise.

+

Since the purpose of done() is consumption rather than transformation, +done() always returns null.

+

+See also

+ +

+ExtendedPromiseInterface::otherwise()

+
$promise->otherwise(callable $onRejected);
+

Registers a rejection handler for promise. It is a shortcut for:

+
$promise->then(null, $onRejected);
+

Additionally, you can type hint the $reason argument of $onRejected to catch +only specific errors.

+
$promise
+    ->otherwise(function (\RuntimeException $reason) {
+        // Only catch \RuntimeException instances
+        // All other types of errors will propagate automatically
+    })
+    ->otherwise(function ($reason) {
+        // Catch other errors
+    )};
+

+ExtendedPromiseInterface::always()

+
$newPromise = $promise->always(callable $onFulfilledOrRejected);
+

Allows you to execute "cleanup" type tasks in a promise chain.

+

It arranges for $onFulfilledOrRejected to be called, with no arguments, +when the promise is either fulfilled or rejected.

+
    +
  • If $promise fulfills, and $onFulfilledOrRejected returns successfully, +$newPromise will fulfill with the same value as $promise.
  • +
  • If $promise fulfills, and $onFulfilledOrRejected throws or returns a +rejected promise, $newPromise will reject with the thrown exception or +rejected promise's reason.
  • +
  • If $promise rejects, and $onFulfilledOrRejected returns successfully, +$newPromise will reject with the same reason as $promise.
  • +
  • If $promise rejects, and $onFulfilledOrRejected throws or returns a +rejected promise, $newPromise will reject with the thrown exception or +rejected promise's reason.
  • +
+

always() behaves similarly to the synchronous finally statement. When combined +with otherwise(), always() allows you to write code that is similar to the familiar +synchronous catch/finally pair.

+

Consider the following synchronous code:

+
try {
+  return doSomething();
+} catch(\Exception $e) {
+    return handleError($e);
+} finally {
+    cleanup();
+}
+

Similar asynchronous code (with doSomething() that returns a promise) can be +written:

+
return doSomething()
+    ->otherwise('handleError')
+    ->always('cleanup');
+

+ExtendedPromiseInterface::progress()

+
+

Deprecated in v2.6.0: Progress support is deprecated and should not be used anymore.

+
+
$promise->progress(callable $onProgress);
+

Registers a handler for progress updates from promise. It is a shortcut for:

+
$promise->then(null, null, $onProgress);
+

+CancellablePromiseInterface

+

A cancellable promise provides a mechanism for consumers to notify the creator +of the promise that they are not longer interested in the result of an +operation.

+

+CancellablePromiseInterface::cancel()

+
$promise->cancel();
+

The cancel() method notifies the creator of the promise that there is no +further interest in the results of the operation.

+

Once a promise is settled (either fulfilled or rejected), calling cancel() on +a promise has no effect.

+

+Implementations

+ +

+Promise

+

Creates a promise whose state is controlled by the functions passed to +$resolver.

+
$resolver = function (callable $resolve, callable $reject, callable $notify) {
+    // Do some work, possibly asynchronously, and then
+    // resolve or reject. You can notify of progress events (deprecated)
+    // along the way if you want/need.
+
+    $resolve($awesomeResult);
+    // or throw new Exception('Promise rejected');
+    // or $resolve($anotherPromise);
+    // or $reject($nastyError);
+    // or $notify($progressNotification);
+};
+
+$canceller = function () {
+    // Cancel/abort any running operations like network connections, streams etc.
+
+    // Reject promise by throwing an exception
+    throw new Exception('Promise cancelled');
+};
+
+$promise = new React\Promise\Promise($resolver, $canceller);
+

The promise constructor receives a resolver function and an optional canceller +function which both will be called with 3 arguments:

+
    +
  • +$resolve($value) - Primary function that seals the fate of the +returned promise. Accepts either a non-promise value, or another promise. +When called with a non-promise value, fulfills promise with that value. +When called with another promise, e.g. $resolve($otherPromise), promise's +fate will be equivalent to that of $otherPromise.
  • +
  • +$reject($reason) - Function that rejects the promise. It is recommended to +just throw an exception instead of using $reject().
  • +
  • +$notify($update) - Deprecated function that issues progress events for the promise.
  • +
+

If the resolver or canceller throw an exception, the promise will be rejected +with that thrown exception as the rejection reason.

+

The resolver function will be called immediately, the canceller function only +once all consumers called the cancel() method of the promise.

+

+FulfilledPromise

+

Creates a already fulfilled promise.

+
$promise = React\Promise\FulfilledPromise($value);
+

Note, that $value cannot be a promise. It's recommended to use +resolve() for creating resolved promises.

+

+RejectedPromise

+

Creates a already rejected promise.

+
$promise = React\Promise\RejectedPromise($reason);
+

Note, that $reason cannot be a promise. It's recommended to use +reject() for creating rejected promises.

+

+LazyPromise

+

Creates a promise which will be lazily initialized by $factory once a consumer +calls the then() method.

+
$factory = function () {
+    $deferred = new React\Promise\Deferred();
+
+    // Do some heavy stuff here and resolve the deferred once completed
+
+    return $deferred->promise();
+};
+
+$promise = new React\Promise\LazyPromise($factory);
+
+// $factory will only be executed once we call then()
+$promise->then(function ($value) {
+});
+

+Functions

+

Useful functions for creating, joining, mapping and reducing collections of +promises.

+

All functions working on promise collections (like all(), race(), some() +etc.) support cancellation. This means, if you call cancel() on the returned +promise, all promises in the collection are cancelled. If the collection itself +is a promise which resolves to an array, this promise is also cancelled.

+

+resolve()

+
$promise = React\Promise\resolve(mixed $promiseOrValue);
+

Creates a promise for the supplied $promiseOrValue.

+

If $promiseOrValue is a value, it will be the resolution value of the +returned promise.

+

If $promiseOrValue is a thenable (any object that provides a then() method), +a trusted promise that follows the state of the thenable is returned.

+

If $promiseOrValue is a promise, it will be returned as is.

+

Note: The promise returned is always a promise implementing +ExtendedPromiseInterface. If you pass in a custom +promise which only implements PromiseInterface, this +promise will be assimilated to a extended promise following $promiseOrValue.

+

+reject()

+
$promise = React\Promise\reject(mixed $promiseOrValue);
+

Creates a rejected promise for the supplied $promiseOrValue.

+

If $promiseOrValue is a value, it will be the rejection value of the +returned promise.

+

If $promiseOrValue is a promise, its completion value will be the rejected +value of the returned promise.

+

This can be useful in situations where you need to reject a promise without +throwing an exception. For example, it allows you to propagate a rejection with +the value of another promise.

+

+all()

+
$promise = React\Promise\all(array|React\Promise\PromiseInterface $promisesOrValues);
+

Returns a promise that will resolve only once all the items in +$promisesOrValues have resolved. The resolution value of the returned promise +will be an array containing the resolution values of each of the items in +$promisesOrValues.

+

+race()

+
$promise = React\Promise\race(array|React\Promise\PromiseInterface $promisesOrValues);
+

Initiates a competitive race that allows one winner. Returns a promise which is +resolved in the same way the first settled promise resolves.

+

+any()

+
$promise = React\Promise\any(array|React\Promise\PromiseInterface $promisesOrValues);
+

Returns a promise that will resolve when any one of the items in +$promisesOrValues resolves. The resolution value of the returned promise +will be the resolution value of the triggering item.

+

The returned promise will only reject if all items in $promisesOrValues are +rejected. The rejection value will be an array of all rejection reasons.

+

The returned promise will also reject with a React\Promise\Exception\LengthException +if $promisesOrValues contains 0 items.

+

+some()

+
$promise = React\Promise\some(array|React\Promise\PromiseInterface $promisesOrValues, integer $howMany);
+

Returns a promise that will resolve when $howMany of the supplied items in +$promisesOrValues resolve. The resolution value of the returned promise +will be an array of length $howMany containing the resolution values of the +triggering items.

+

The returned promise will reject if it becomes impossible for $howMany items +to resolve (that is, when (count($promisesOrValues) - $howMany) + 1 items +reject). The rejection value will be an array of +(count($promisesOrValues) - $howMany) + 1 rejection reasons.

+

The returned promise will also reject with a React\Promise\Exception\LengthException +if $promisesOrValues contains less items than $howMany.

+

+map()

+
$promise = React\Promise\map(array|React\Promise\PromiseInterface $promisesOrValues, callable $mapFunc);
+

Traditional map function, similar to array_map(), but allows input to contain +promises and/or values, and $mapFunc may return either a value or a promise.

+

The map function receives each item as argument, where item is a fully resolved +value of a promise or value in $promisesOrValues.

+

+reduce()

+
$promise = React\Promise\reduce(array|React\Promise\PromiseInterface $promisesOrValues, callable $reduceFunc , $initialValue = null);
+

Traditional reduce function, similar to array_reduce(), but input may contain +promises and/or values, and $reduceFunc may return either a value or a +promise, and $initialValue may be a promise or a value for the starting +value.

+

+PromisorInterface

+

The React\Promise\PromisorInterface provides a common interface for objects +that provide a promise. React\Promise\Deferred implements it, but since it +is part of the public API anyone can implement it.

+

+Examples

+

+How to use Deferred

+
function getAwesomeResultPromise()
+{
+    $deferred = new React\Promise\Deferred();
+
+    // Execute a Node.js-style function using the callback pattern
+    computeAwesomeResultAsynchronously(function ($error, $result) use ($deferred) {
+        if ($error) {
+            $deferred->reject($error);
+        } else {
+            $deferred->resolve($result);
+        }
+    });
+
+    // Return the promise
+    return $deferred->promise();
+}
+
+getAwesomeResultPromise()
+    ->then(
+        function ($value) {
+            // Deferred resolved, do something with $value
+        },
+        function ($reason) {
+            // Deferred rejected, do something with $reason
+        },
+        function ($update) {
+            // Progress notification triggered, do something with $update
+        }
+    );
+

+How promise forwarding works

+

A few simple examples to show how the mechanics of Promises/A forwarding works. +These examples are contrived, of course, and in real usage, promise chains will +typically be spread across several function calls, or even several levels of +your application architecture.

+

+Resolution forwarding

+

Resolved promises forward resolution values to the next promise. +The first promise, $deferred->promise(), will resolve with the value passed +to $deferred->resolve() below.

+

Each call to then() returns a new promise that will resolve with the return +value of the previous handler. This creates a promise "pipeline".

+
$deferred = new React\Promise\Deferred();
+
+$deferred->promise()
+    ->then(function ($x) {
+        // $x will be the value passed to $deferred->resolve() below
+        // and returns a *new promise* for $x + 1
+        return $x + 1;
+    })
+    ->then(function ($x) {
+        // $x === 2
+        // This handler receives the return value of the
+        // previous handler.
+        return $x + 1;
+    })
+    ->then(function ($x) {
+        // $x === 3
+        // This handler receives the return value of the
+        // previous handler.
+        return $x + 1;
+    })
+    ->then(function ($x) {
+        // $x === 4
+        // This handler receives the return value of the
+        // previous handler.
+        echo 'Resolve ' . $x;
+    });
+
+$deferred->resolve(1); // Prints "Resolve 4"
+

+Rejection forwarding

+

Rejected promises behave similarly, and also work similarly to try/catch: +When you catch an exception, you must rethrow for it to propagate.

+

Similarly, when you handle a rejected promise, to propagate the rejection, +"rethrow" it by either returning a rejected promise, or actually throwing +(since promise translates thrown exceptions into rejections)

+
$deferred = new React\Promise\Deferred();
+
+$deferred->promise()
+    ->then(function ($x) {
+        throw new \Exception($x + 1);
+    })
+    ->otherwise(function (\Exception $x) {
+        // Propagate the rejection
+        throw $x;
+    })
+    ->otherwise(function (\Exception $x) {
+        // Can also propagate by returning another rejection
+        return React\Promise\reject(
+            new \Exception($x->getMessage() + 1)
+        );
+    })
+    ->otherwise(function ($x) {
+        echo 'Reject ' . $x->getMessage(); // 3
+    });
+
+$deferred->resolve(1);  // Prints "Reject 3"
+

+Mixed resolution and rejection forwarding

+

Just like try/catch, you can choose to propagate or not. Mixing resolutions and +rejections will still forward handler results in a predictable way.

+
$deferred = new React\Promise\Deferred();
+
+$deferred->promise()
+    ->then(function ($x) {
+        return $x + 1;
+    })
+    ->then(function ($x) {
+        throw new \Exception($x + 1);
+    })
+    ->otherwise(function (\Exception $x) {
+        // Handle the rejection, and don't propagate.
+        // This is like catch without a rethrow
+        return $x->getMessage() + 1;
+    })
+    ->then(function ($x) {
+        echo 'Mixed ' . $x; // 4
+    });
+
+$deferred->resolve(1);  // Prints "Mixed 4"
+

+Progress event forwarding

+
+

Deprecated in v2.6.0: Progress support is deprecated and should not be used anymore.

+
+

In the same way as resolution and rejection handlers, your progress handler +MUST return a progress event to be propagated to the next link in the chain. +If you return nothing, null will be propagated.

+

Also in the same way as resolutions and rejections, if you don't register a +progress handler, the update will be propagated through.

+

If your progress handler throws an exception, the exception will be propagated +to the next link in the chain. The best thing to do is to ensure your progress +handlers do not throw exceptions.

+

This gives you the opportunity to transform progress events at each step in the +chain so that they are meaningful to the next step. It also allows you to choose +not to transform them, and simply let them propagate untransformed, by not +registering a progress handler.

+
$deferred = new React\Promise\Deferred();
+
+$deferred->promise()
+    ->progress(function ($update) {
+        return $update + 1;
+    })
+    ->progress(function ($update) {
+        echo 'Progress ' . $update; // 2
+    });
+
+$deferred->notify(1);  // Prints "Progress 2"
+

+done() vs. then()

+

The golden rule is:

+
Either return your promise, or call done() on it.
+
+

At a first glance, then() and done() seem very similar. However, there are +important distinctions.

+

The intent of then() is to transform a promise's value and to pass or return +a new promise for the transformed value along to other parts of your code.

+

The intent of done() is to consume a promise's value, transferring +responsibility for the value to your code.

+

In addition to transforming a value, then() allows you to recover from, or +propagate intermediate errors. Any errors that are not handled will be caught +by the promise machinery and used to reject the promise returned by then().

+

Calling done() transfers all responsibility for errors to your code. If an +error (either a thrown exception or returned rejection) escapes the +$onFulfilled or $onRejected callbacks you provide to done, it will be +rethrown in an uncatchable way causing a fatal error.

+
function getJsonResult()
+{
+    return queryApi()
+        ->then(
+            // Transform API results to an object
+            function ($jsonResultString) {
+                return json_decode($jsonResultString);
+            },
+            // Transform API errors to an exception
+            function ($jsonErrorString) {
+                $object = json_decode($jsonErrorString);
+                throw new ApiErrorException($object->errorMessage);
+            }
+        );
+}
+
+// Here we provide no rejection handler. If the promise returned has been
+// rejected, the ApiErrorException will be thrown
+getJsonResult()
+    ->done(
+        // Consume transformed object
+        function ($jsonResultObject) {
+            // Do something with $jsonResultObject
+        }
+    );
+
+// Here we provide a rejection handler which will either throw while debugging
+// or log the exception
+getJsonResult()
+    ->done(
+        function ($jsonResultObject) {
+            // Do something with $jsonResultObject
+        },
+        function (ApiErrorException $exception) {
+            if (isDebug()) {
+                throw $exception;
+            } else {
+                logException($exception);
+            }
+        }
+    );
+

Note that if a rejection value is not an instance of \Exception, it will be +wrapped in an exception of the type React\Promise\UnhandledRejectionException.

+

You can get the original rejection reason by calling $exception->getReason().

+

+Install

+

The recommended way to install this library is through Composer. +New to Composer?

+

This project follows SemVer. +This will install the latest supported version:

+
$ composer require react/promise:^2.7
+

See also the CHANGELOG for details about version upgrades.

+

This project aims to run on any platform and thus does not require any PHP +extensions and supports running on legacy PHP 5.4 through current PHP 7+ and HHVM. +It's highly recommended to use PHP 7+ for this project due to its vast +performance improvements.

+

+Credits

+

Promise is a port of when.js +by Brian Cavalier.

+

Also, large parts of the documentation have been ported from the when.js +Wiki and the +API docs.

+

+License

+

Released under the MIT license.

+
+ +
+
+
+ + + + + + diff --git a/promise/license.html b/promise/license.html new file mode 100644 index 000000000..d04af313b --- /dev/null +++ b/promise/license.html @@ -0,0 +1,475 @@ + + + + + + + + Promise: License - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

Promise License

+ +

Copyright (c) 2012-2016 Jan Sorgalla

+

Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions:

+

The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software.

+

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE.

+
+ +
+
+
+ + + + + + diff --git a/robots.txt b/robots.txt new file mode 100644 index 000000000..eb0536286 --- /dev/null +++ b/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: diff --git a/safari-pinned-tab.svg b/safari-pinned-tab.svg new file mode 100644 index 000000000..f0ec49309 --- /dev/null +++ b/safari-pinned-tab.svg @@ -0,0 +1 @@ + diff --git a/socket/changelog.html b/socket/changelog.html new file mode 100644 index 000000000..d7fd2f004 --- /dev/null +++ b/socket/changelog.html @@ -0,0 +1,1617 @@ + + + + + + + + Socket: Changelog - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

Socket Changelog

+ + + +

+ + 2018 +

+ + +

+ + + 0.8.12 + + + (2018-06-11) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Improve memory consumption for failed and cancelled connection attempts.
    +(#161 by @clue)

    +
  • +
  • +

    Improve test suite to fix Travis config to test against legacy PHP 5.3 again.
    +(#162 by @clue)

    +
  • +
+ +
+ +

+ + + 0.8.11 + + + (2018-04-24) + + Release on GitHub + + +

+ +
    +
  • Feature: Improve memory consumption for cancelled connection attempts and
    +simplify skipping DNS lookup when connecting to IP addresses.
    +(#159 and #160 by @clue)
  • +
+ +
+ +

+ + + 0.8.10 + + + (2018-02-28) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Update DNS dependency to support loading system default DNS
    +nameserver config on all supported platforms
    +(/etc/resolv.conf on Unix/Linux/Mac/Docker/WSL and WMIC on Windows)
    +(#152 by @clue)

    +

    This means that connecting to hosts that are managed by a local DNS server,
    +such as a corporate DNS server or when using Docker containers, will now
    +work as expected across all platforms with no changes required:

    +
    $connector = new Connector($loop);
    +$connector->connect('intranet.example:80')->then(function ($connection) {
    +    //
    +});
    +
  • +
+ +
+ +

+ + + 0.8.9 + + + (2018-01-18) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Support explicitly choosing TLS version to negotiate with remote side
    +by respecting crypto_method context parameter for all classes.
    +(#149 by @clue)

    +

    By default, all connector and server classes support TLSv1.0+ and exclude
    +support for legacy SSLv2/SSLv3. As of PHP 5.6+ you can also explicitly
    +choose the TLS version you want to negotiate with the remote side:

    +
    // new: now supports 'crypto_method` context parameter for all classes
    +$connector = new Connector($loop, array(
    +    'tls' => array(
    +        'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
    +    )
    +));
    +
  • +
  • +

    Minor internal clean up to unify class imports
    +(#148 by @clue)

    +
  • +
+ +
+ +

+ + + 0.8.8 + + + (2018-01-06) + + Release on GitHub + + +

+ +
    +
  • Improve test suite by adding test group to skip integration tests relying on
    +internet connection and fix minor documentation typo.
    +(#146 by @clue and #145 by @cn007b)
  • +
+ +
+

+ + 2017 +

+ + +

+ + + 0.8.7 + + + (2017-12-24) + + Release on GitHub + + +

+ +
    +
  • +

    Fix: Fix closing socket resource before removing from loop
    +(#141 by @clue)

    +

    This fixes the root cause of an uncaught Exception that only manifested
    +itself after the recent Stream v0.7.4 component update and only if you're
    +using ext-event (ExtEventLoop).

    +
  • +
  • +

    Improve test suite by testing against PHP 7.2
    +(#140 by @carusogabriel)

    +
  • +
+ +
+ +

+ + + 0.8.6 + + + (2017-11-18) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Add Unix domain socket (UDS) support to Server with unix:// URI scheme
    +and add advanced UnixServer class.
    +(#120 by @andig)

    +
    // new: Server now supports "unix://" scheme
    +$server = new Server('unix:///tmp/server.sock', $loop);
    +
    +// new: advanced usage
    +$server = new UnixServer('/tmp/server.sock', $loop);
    +
  • +
  • +

    Restructure examples to ease getting started
    +(#136 by @clue)

    +
  • +
  • +

    Improve test suite by adding forward compatibility with PHPUnit 6 and
    +ignore Mac OS X test failures for now until Travis tests work again
    +(#133 by @gabriel-caruso and #134 by @clue)

    +
  • +
+ +
+ +

+ + + 0.8.5 + + + (2017-10-23) + + Release on GitHub + + +

+ +
    +
  • +

    Fix: Work around PHP bug with Unix domain socket (UDS) paths for Mac OS X
    +(#123 by @andig)

    +
  • +
  • +

    Fix: Fix SecureServer to return null URI if server socket is already closed
    +(#129 by @clue)

    +
  • +
  • +

    Improve test suite by adding forward compatibility with PHPUnit v5 and
    +forward compatibility with upcoming EventLoop releases in tests and
    +test Mac OS X on Travis
    +(#122 by @andig and #125, #127 and #130 by @clue)

    +
  • +
  • +

    Readme improvements
    +(#118 by @jsor)

    +
  • +
+ +
+ +

+ + + 0.8.4 + + + (2017-09-16) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Add FixedUriConnector decorator to use fixed, preconfigured URI instead
    +(#117 by @clue)

    +

    This can be useful for consumers that do not support certain URIs, such as
    +when you want to explicitly connect to a Unix domain socket (UDS) path
    +instead of connecting to a default address assumed by an higher-level API:

    +
    $connector = new FixedUriConnector(
    +    'unix:///var/run/docker.sock',
    +    new UnixConnector($loop)
    +);
    +
    +// destination will be ignored, actually connects to Unix domain socket
    +$promise = $connector->connect('localhost:80');
    +
  • +
+ +
+ +

+ + + 0.8.3 + + + (2017-09-08) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Reduce memory consumption for failed connections
    +(#113 by @valga)

    +
  • +
  • +

    Fix: Work around write chunk size for TLS streams for PHP < 7.1.14
    +(#114 by @clue)

    +
  • +
+ +
+ +

+ + + 0.8.2 + + + (2017-08-25) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Update DNS dependency to support hosts file on all platforms
    +(#112 by @clue)

    +

    This means that connecting to hosts such as localhost will now work as
    +expected across all platforms with no changes required:

    +
    $connector = new Connector($loop);
    +$connector->connect('localhost:8080')->then(function ($connection) {
    +    //
    +});
    +
  • +
+ +
+ +

+ + + 0.8.1 + + + (2017-08-15) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Forward compatibility with upcoming EventLoop v1.0 and v0.5 and
    +target evenement 3.0 a long side 2.0 and 1.0
    +(#104 by @clue and #111 by @WyriHaximus)

    +
  • +
  • +

    Improve test suite by locking Travis distro so new defaults will not break the build and
    +fix HHVM build for now again and ignore future HHVM build errors
    +(#109 and #110 by @clue)

    +
  • +
  • +

    Minor documentation fixes
    +(#103 by @christiaan and #108 by @hansott)

    +
  • +
+ +
+ +

+ + + 0.8.0 + + + (2017-05-09) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: New Server class now acts as a facade for existing server classes
    +and renamed old Server to TcpServer for advanced usage.
    +(#96 and #97 by @clue)

    +

    The Server class is now the main class in this package that implements the
    +ServerInterface and allows you to accept incoming streaming connections,
    +such as plaintext TCP/IP or secure TLS connection streams.

    +
    +

    This is not a BC break and consumer code does not have to be updated.

    +
    +
  • +
  • +

    Feature / BC break: All addresses are now URIs that include the URI scheme
    +(#98 by @clue)

    +
    - $parts = parse_url('tcp://' . $conn->getRemoteAddress());
    ++ $parts = parse_url($conn->getRemoteAddress());
    +
  • +
  • +

    Fix: Fix unix:// addresses for Unix domain socket (UDS) paths
    +(#100 by @clue)

    +
  • +
  • +

    Feature: Forward compatibility with Stream v1.0 and v0.7
    +(#99 by @clue)

    +
  • +
+ +
+ +

+ + + 0.7.2 + + + (2017-04-24) + + Release on GitHub + + +

+ +
    +
  • Fix: Work around latest PHP 7.0.18 and 7.1.4 no longer accepting full URIs
    +(#94 by @clue)
  • +
+ +
+ +

+ + + 0.7.1 + + + (2017-04-10) + + Release on GitHub + + +

+ +
    +
  • Fix: Ignore HHVM errors when closing connection that is already closing
    +(#91 by @clue)
  • +
+ +
+ +

+ + + 0.7.0 + + + (2017-04-10) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Merge SocketClient component into this component
    +(#87 by @clue)

    +

    This means that this package now provides async, streaming plaintext TCP/IP
    +and secure TLS socket server and client connections for ReactPHP.

    +
    $connector = new React\Socket\Connector($loop);
    +$connector->connect('google.com:80')->then(function (ConnectionInterface $conn) {
    +    $connection->write('');
    +});
    +

    Accordingly, the ConnectionInterface is now used to represent both incoming
    +server side connections as well as outgoing client side connections.

    +

    If you've previously used the SocketClient component to establish outgoing
    +client connections, upgrading should take no longer than a few minutes.
    +All classes have been merged as-is from the latest v0.7.0 release with no
    +other changes, so you can simply update your code to use the updated namespace
    +like this:

    +
    // old from SocketClient component and namespace
    +$connector = new React\SocketClient\Connector($loop);
    +$connector->connect('google.com:80')->then(function (ConnectionInterface $conn) {
    +    $connection->write('');
    +});
    +
    +// new
    +$connector = new React\Socket\Connector($loop);
    +$connector->connect('google.com:80')->then(function (ConnectionInterface $conn) {
    +    $connection->write('');
    +});
    +
  • +
+ +
+ +

+ + + 0.6.0 + + + (2017-04-04) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Add LimitingServer to limit and keep track of open connections
    +(#86 by @clue)

    +
    $server = new Server(0, $loop);
    +$server = new LimitingServer($server, 100);
    +
    +$server->on('connection', function (ConnectionInterface $connection) {
    +    $connection->write('hello there!' . PHP_EOL);
    +
    +});
    +
  • +
  • +

    Feature / BC break: Add pause() and resume() methods to limit active
    +connections
    +(#84 by @clue)

    +
    $server = new Server(0, $loop);
    +$server->pause();
    +
    +$loop->addTimer(1.0, function() use ($server) {
    +    $server->resume();
    +});
    +
  • +
+ +
+ +

+ + + 0.5.1 + + + (2017-03-09) + + Release on GitHub + + +

+ +
    +
  • Feature: Forward compatibility with Stream v0.5 and upcoming v0.6
    +(#79 by @clue)
  • +
+ +
+ +

+ + + 0.5.0 + + + (2017-02-14) + + Release on GitHub + + +

+ +
    +
  • +

    Feature / BC break: Replace listen() call with URIs passed to constructor
    +and reject listening on hostnames with InvalidArgumentException
    +and replace ConnectionException with RuntimeException for consistency
    +(#61, #66 and #72 by @clue)

    +
    // old
    +$server = new Server($loop);
    +$server->listen(8080);
    +
    +// new
    +$server = new Server(8080, $loop);
    +

    Similarly, you can now pass a full listening URI to the constructor to change
    +the listening host:

    +
    // old
    +$server = new Server($loop);
    +$server->listen(8080, '127.0.0.1');
    +
    +// new
    +$server = new Server('127.0.0.1:8080', $loop);
    +

    Trying to start listening on (DNS) host names will now throw an
    +InvalidArgumentException, use IP addresses instead:

    +
    // old
    +$server = new Server($loop);
    +$server->listen(8080, 'localhost');
    +
    +// new
    +$server = new Server('127.0.0.1:8080', $loop);
    +

    If trying to listen fails (such as if port is already in use or port below
    +1024 may require root access etc.), it will now throw a RuntimeException,
    +the ConnectionException class has been removed:

    +
    // old: throws React\Socket\ConnectionException
    +$server = new Server($loop);
    +$server->listen(80);
    +
    +// new: throws RuntimeException
    +$server = new Server(80, $loop);
    +
  • +
  • +

    Feature / BC break: Rename shutdown() to close() for consistency throughout React
    +(#62 by @clue)

    +
    // old
    +$server->shutdown();
    +
    +// new
    +$server->close();
    +
  • +
  • +

    Feature / BC break: Replace getPort() with getAddress()
    +(#67 by @clue)

    +
    // old
    +echo $server->getPort(); // 8080
    +
    +// new
    +echo $server->getAddress(); // 127.0.0.1:8080
    +
  • +
  • +

    Feature / BC break: getRemoteAddress() returns full address instead of only IP
    +(#65 by @clue)

    +
    // old
    +echo $connection->getRemoteAddress(); // 192.168.0.1
    +
    +// new
    +echo $connection->getRemoteAddress(); // 192.168.0.1:51743
    +
  • +
  • +

    Feature / BC break: Add getLocalAddress() method
    +(#68 by @clue)

    +
    echo $connection->getLocalAddress(); // 127.0.0.1:8080
    +
  • +
  • +

    BC break: The Server and SecureServer class are now marked final
    +and you can no longer extend them
    +(which was never documented or recommended anyway).
    +Public properties and event handlers are now internal only.
    +Please use composition instead of extension.
    +(#71, #70 and #69 by @clue)

    +
  • +
+ +
+ +

+ + + 0.4.6 + + + (2017-01-26) + + Release on GitHub + + +

+ +
    +
  • Feature: Support socket context options passed to Server
    +(#64 by @clue)
  • +
  • Fix: Properly return null for unknown addresses
    +(#63 by @clue)
  • +
  • Improve documentation for ServerInterface and lock test suite requirements
    +(#60 by @clue, #57 by @shaunbramley)
  • +
+ +
+ +

+ + + 0.4.5 + + + (2017-01-08) + + Release on GitHub + + +

+ +
    +
  • Feature: Add SecureServer for secure TLS connections
    +(#55 by @clue)
  • +
  • Add functional integration tests
    +(#54 by @clue)
  • +
+ +
+

+ + 2016 +

+ + +

+ + + 0.4.4 + + + (2016-12-19) + + Release on GitHub + + +

+ +
    +
  • Feature / Fix: ConnectionInterface should extend DuplexStreamInterface + documentation
    +(#50 by @clue)
  • +
  • Feature / Fix: Improve test suite and switch to normal stream handler
    +(#51 by @clue)
  • +
  • Feature: Add examples
    +(#49 by @clue)
  • +
+ +
+ +

+ + + 0.4.3 + + + (2016-03-01) + + Release on GitHub + + +

+ +
    +
  • Suppress errors on stream_socket_accept to prevent PHP from crashing
  • +
  • Support for PHP7 and HHVM
  • +
  • Support PHP 5.3 again
  • +
+ +
+

+ + 2014 +

+ + +

+ + + 0.4.2 + + + (2014-05-25) + + Release on GitHub + + +

+ +
    +
  • [Connection] Verify stream is valid resource
  • +
+ +
+ +

+ + + 0.4.1 + + + (2014-04-13) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Check read buffer for data before shutdown signal and end emit (@artydev)
  • +
  • Bug fix: v0.3.4 changes merged for v0.4.1
  • +
+ +
+ +

+ + + 0.3.4 + + + (2014-02-17) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Reset socket to non-blocking after shutting down (PHP bug)
  • +
+ +
+ +

+ + + 0.4.0 + + + (2014-02-02) + + Release on GitHub + + +

+ +
    +
  • BC break: Bump minimum PHP version to PHP 5.4, remove 5.3 specific hacks
  • +
  • BC break: Update to React/Promise 2.0
  • +
  • BC break: Update to Evenement 2.0
  • +
  • Dependency: Autoloading and filesystem structure now PSR-4 instead of PSR-0
  • +
  • Bump React dependencies to v0.4
  • +
+ +
+

+ + 2013 +

+ + +

+ + + 0.3.3 + + + (2013-07-08) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + 0.3.2 + + + (2013-04-26) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + 0.3.1 + + + (2013-04-20) + + Release on GitHub + + +

+ +
    +
  • Feature: Support binding to IPv6 addresses (@clue)
  • +
+ +
+ +

+ + + 0.3.0 + + + (2013-01-21) + + Release on GitHub + + +

+ +
    +
  • Bump React dependencies to v0.3
  • +
+ +
+

+ + 2012 +

+ + +

+ + + 0.2.6 + + + (2012-12-14) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + 0.2.3 + + + (2012-11-05) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + 0.2.0 + + + (2012-09-10) + + Release on GitHub + + +

+ +
    +
  • Bump React dependencies to v0.2
  • +
+ +
+ +

+ + + 0.1.1 + + + (2012-07-12) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + 0.1.0 + + + (2012-07-11) + + Release on GitHub + + +

+ +
    +
  • First tagged release
  • +
+ +
+
+ +
+
+
+ + + + + + diff --git a/socket/index.html b/socket/index.html new file mode 100644 index 000000000..2adf58809 --- /dev/null +++ b/socket/index.html @@ -0,0 +1,1683 @@ + + + + + + + + Socket: +Socket - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

Socket

+ + +

Build Status

+

Async, streaming plaintext TCP/IP and secure TLS socket server and client +connections for ReactPHP.

+

The socket library provides re-usable interfaces for a socket-layer +server and client based on the EventLoop +and Stream components. +Its server component allows you to build networking servers that accept incoming +connections from networking clients (such as an HTTP server). +Its client component allows you to build networking clients that establish +outgoing connections to networking servers (such as an HTTP or database client). +This library provides async, streaming means for all of this, so you can +handle multiple concurrent connections without blocking.

+

Table of Contents

+ +

+Quickstart example

+

Here is a server that closes the connection if you send it anything:

+
$loop = React\EventLoop\Factory::create();
+$socket = new React\Socket\Server('127.0.0.1:8080', $loop);
+
+$socket->on('connection', function (ConnectionInterface $conn) {
+    $conn->write("Hello " . $conn->getRemoteAddress() . "!\n");
+    $conn->write("Welcome to this amazing server!\n");
+    $conn->write("Here's a tip: don't say anything.\n");
+
+    $conn->on('data', function ($data) use ($conn) {
+        $conn->close();
+    });
+});
+
+$loop->run();
+

See also the examples.

+

Here's a client that outputs the output of said server and then attempts to +send it a string:

+
$loop = React\EventLoop\Factory::create();
+$connector = new React\Socket\Connector($loop);
+
+$connector->connect('127.0.0.1:8080')->then(function (ConnectionInterface $conn) use ($loop) {
+    $conn->pipe(new React\Stream\WritableResourceStream(STDOUT, $loop));
+    $conn->write("Hello World!\n");
+});
+
+$loop->run();
+

+Connection usage

+

+ConnectionInterface

+

The ConnectionInterface is used to represent any incoming and outgoing +connection, such as a normal TCP/IP connection.

+

An incoming or outgoing connection is a duplex stream (both readable and +writable) that implements React's +DuplexStreamInterface. +It contains additional properties for the local and remote address (client IP) +where this connection has been established to/from.

+

Most commonly, instances implementing this ConnectionInterface are emitted +by all classes implementing the ServerInterface and +used by all classes implementing the ConnectorInterface.

+

Because the ConnectionInterface implements the underlying +DuplexStreamInterface +you can use any of its events and methods as usual:

+
$connection->on('data', function ($chunk) {
+    echo $chunk;
+});
+
+$connection->on('end', function () {
+    echo 'ended';
+});
+
+$connection->on('error', function (Exception $e) {
+    echo 'error: ' . $e->getMessage();
+});
+
+$connection->on('close', function () {
+    echo 'closed';
+});
+
+$connection->write($data);
+$connection->end($data = null);
+$connection->close();
+//
+

For more details, see the +DuplexStreamInterface.

+

+getRemoteAddress()

+

The getRemoteAddress(): ?string method returns the full remote address +(URI) where this connection has been established with.

+
$address = $connection->getRemoteAddress();
+echo 'Connection with ' . $address . PHP_EOL;
+

If the remote address can not be determined or is unknown at this time (such as +after the connection has been closed), it MAY return a NULL value instead.

+

Otherwise, it will return the full address (URI) as a string value, such +as tcp://127.0.0.1:8080, tcp://[::1]:80, tls://127.0.0.1:443, +unix://example.sock or unix:///path/to/example.sock. +Note that individual URI components are application specific and depend +on the underlying transport protocol.

+

If this is a TCP/IP based connection and you only want the remote IP, you may +use something like this:

+
$address = $connection->getRemoteAddress();
+$ip = trim(parse_url($address, PHP_URL_HOST), '[]');
+echo 'Connection with ' . $ip . PHP_EOL;
+

+getLocalAddress()

+

The getLocalAddress(): ?string method returns the full local address +(URI) where this connection has been established with.

+
$address = $connection->getLocalAddress();
+echo 'Connection with ' . $address . PHP_EOL;
+

If the local address can not be determined or is unknown at this time (such as +after the connection has been closed), it MAY return a NULL value instead.

+

Otherwise, it will return the full address (URI) as a string value, such +as tcp://127.0.0.1:8080, tcp://[::1]:80, tls://127.0.0.1:443, +unix://example.sock or unix:///path/to/example.sock. +Note that individual URI components are application specific and depend +on the underlying transport protocol.

+

This method complements the getRemoteAddress() method, +so they should not be confused.

+

If your TcpServer instance is listening on multiple interfaces (e.g. using +the address 0.0.0.0), you can use this method to find out which interface +actually accepted this connection (such as a public or local interface).

+

If your system has multiple interfaces (e.g. a WAN and a LAN interface), +you can use this method to find out which interface was actually +used for this connection.

+

+Server usage

+

+ServerInterface

+

The ServerInterface is responsible for providing an interface for accepting +incoming streaming connections, such as a normal TCP/IP connection.

+

Most higher-level components (such as a HTTP server) accept an instance +implementing this interface to accept incoming streaming connections. +This is usually done via dependency injection, so it's fairly simple to actually +swap this implementation against any other implementation of this interface. +This means that you SHOULD typehint against this interface instead of a concrete +implementation of this interface.

+

Besides defining a few methods, this interface also implements the +EventEmitterInterface +which allows you to react to certain events.

+

+connection event

+

The connection event will be emitted whenever a new connection has been +established, i.e. a new client connects to this server socket:

+
$server->on('connection', function (ConnectionInterface $connection) {
+    echo 'new connection' . PHP_EOL;
+});
+

See also the ConnectionInterface for more details +about handling the incoming connection.

+

+error event

+

The error event will be emitted whenever there's an error accepting a new +connection from a client.

+
$server->on('error', function (Exception $e) {
+    echo 'error: ' . $e->getMessage() . PHP_EOL;
+});
+

Note that this is not a fatal error event, i.e. the server keeps listening for +new connections even after this event.

+

+getAddress()

+

The getAddress(): ?string method can be used to +return the full address (URI) this server is currently listening on.

+
$address = $server->getAddress();
+echo 'Server listening on ' . $address . PHP_EOL;
+

If the address can not be determined or is unknown at this time (such as +after the socket has been closed), it MAY return a NULL value instead.

+

Otherwise, it will return the full address (URI) as a string value, such +as tcp://127.0.0.1:8080, tcp://[::1]:80, tls://127.0.0.1:443 +unix://example.sock or unix:///path/to/example.sock. +Note that individual URI components are application specific and depend +on the underlying transport protocol.

+

If this is a TCP/IP based server and you only want the local port, you may +use something like this:

+
$address = $server->getAddress();
+$port = parse_url($address, PHP_URL_PORT);
+echo 'Server listening on port ' . $port . PHP_EOL;
+

+pause()

+

The pause(): void method can be used to +pause accepting new incoming connections.

+

Removes the socket resource from the EventLoop and thus stop accepting +new connections. Note that the listening socket stays active and is not +closed.

+

This means that new incoming connections will stay pending in the +operating system backlog until its configurable backlog is filled. +Once the backlog is filled, the operating system may reject further +incoming connections until the backlog is drained again by resuming +to accept new connections.

+

Once the server is paused, no futher connection events SHOULD +be emitted.

+
$server->pause();
+
+$server->on('connection', assertShouldNeverCalled());
+

This method is advisory-only, though generally not recommended, the +server MAY continue emitting connection events.

+

Unless otherwise noted, a successfully opened server SHOULD NOT start +in paused state.

+

You can continue processing events by calling resume() again.

+

Note that both methods can be called any number of times, in particular +calling pause() more than once SHOULD NOT have any effect. +Similarly, calling this after close() is a NO-OP.

+

+resume()

+

The resume(): void method can be used to +resume accepting new incoming connections.

+

Re-attach the socket resource to the EventLoop after a previous pause().

+
$server->pause();
+
+$loop->addTimer(1.0, function () use ($server) {
+    $server->resume();
+});
+

Note that both methods can be called any number of times, in particular +calling resume() without a prior pause() SHOULD NOT have any effect. +Similarly, calling this after close() is a NO-OP.

+

+close()

+

The close(): void method can be used to +shut down this listening socket.

+

This will stop listening for new incoming connections on this socket.

+
echo 'Shutting down server socket' . PHP_EOL;
+$server->close();
+

Calling this method more than once on the same instance is a NO-OP.

+

+Server

+

The Server class is the main class in this package that implements the +ServerInterface and allows you to accept incoming +streaming connections, such as plaintext TCP/IP or secure TLS connection streams. +Connections can also be accepted on Unix domain sockets.

+
$server = new Server(8080, $loop);
+

As above, the $uri parameter can consist of only a port, in which case the +server will default to listening on the localhost address 127.0.0.1, +which means it will not be reachable from outside of this system.

+

In order to use a random port assignment, you can use the port 0:

+
$server = new Server(0, $loop);
+$address = $server->getAddress();
+

In order to change the host the socket is listening on, you can provide an IP +address through the first parameter provided to the constructor, optionally +preceded by the tcp:// scheme:

+
$server = new Server('192.168.0.1:8080', $loop);
+

If you want to listen on an IPv6 address, you MUST enclose the host in square +brackets:

+
$server = new Server('[::1]:8080', $loop);
+

To listen on a Unix domain socket (UDS) path, you MUST prefix the URI with the +unix:// scheme:

+
$server = new Server('unix:///tmp/server.sock', $loop);
+

If the given URI is invalid, does not contain a port, any other scheme or if it +contains a hostname, it will throw an InvalidArgumentException:

+
// throws InvalidArgumentException due to missing port
+$server = new Server('127.0.0.1', $loop);
+

If the given URI appears to be valid, but listening on it fails (such as if port +is already in use or port below 1024 may require root access etc.), it will +throw a RuntimeException:

+
$first = new Server(8080, $loop);
+
+// throws RuntimeException because port is already in use
+$second = new Server(8080, $loop);
+
+

Note that these error conditions may vary depending on your system and/or +configuration. +See the exception message and code for more details about the actual error +condition.

+
+

Optionally, you can specify TCP socket context options +for the underlying stream socket resource like this:

+
$server = new Server('[::1]:8080', $loop, array(
+    'tcp' => array(
+        'backlog' => 200,
+        'so_reuseport' => true,
+        'ipv6_v6only' => true
+    )
+));
+
+

Note that available socket context options, +their defaults and effects of changing these may vary depending on your system +and/or PHP version. +Passing unknown context options has no effect. +For BC reasons, you can also pass the TCP socket context options as a simple +array without wrapping this in another array under the tcp key.

+
+

You can start a secure TLS (formerly known as SSL) server by simply prepending +the tls:// URI scheme. +Internally, it will wait for plaintext TCP/IP connections and then performs a +TLS handshake for each connection. +It thus requires valid TLS context options, +which in its most basic form may look something like this if you're using a +PEM encoded certificate file:

+
$server = new Server('tls://127.0.0.1:8080', $loop, array(
+    'tls' => array(
+        'local_cert' => 'server.pem'
+    )
+));
+
+

Note that the certificate file will not be loaded on instantiation but when an +incoming connection initializes its TLS context. +This implies that any invalid certificate file paths or contents will only cause +an error event at a later time.

+
+

If your private key is encrypted with a passphrase, you have to specify it +like this:

+
$server = new Server('tls://127.0.0.1:8000', $loop, array(
+    'tls' => array(
+        'local_cert' => 'server.pem',
+        'passphrase' => 'secret'
+    )
+));
+

By default, this server supports TLSv1.0+ and excludes support for legacy +SSLv2/SSLv3. As of PHP 5.6+ you can also explicitly choose the TLS version you +want to negotiate with the remote side:

+
$server = new Server('tls://127.0.0.1:8000', $loop, array(
+    'tls' => array(
+        'local_cert' => 'server.pem',
+        'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_SERVER
+    )
+));
+
+

Note that available TLS context options, +their defaults and effects of changing these may vary depending on your system +and/or PHP version. +The outer context array allows you to also use tcp (and possibly more) +context options at the same time. +Passing unknown context options has no effect. +If you do not use the tls:// scheme, then passing tls context options +has no effect.

+
+

Whenever a client connects, it will emit a connection event with a connection +instance implementing ConnectionInterface:

+
$server->on('connection', function (ConnectionInterface $connection) {
+    echo 'Plaintext connection from ' . $connection->getRemoteAddress() . PHP_EOL;
+    
+    $connection->write('hello there!' . PHP_EOL);
+
+});
+

See also the ServerInterface for more details.

+
+

Note that the Server class is a concrete implementation for TCP/IP sockets. +If you want to typehint in your higher-level protocol implementation, you SHOULD +use the generic ServerInterface instead.

+
+

+Advanced server usage

+

+TcpServer

+

The TcpServer class implements the ServerInterface and +is responsible for accepting plaintext TCP/IP connections.

+
$server = new TcpServer(8080, $loop);
+

As above, the $uri parameter can consist of only a port, in which case the +server will default to listening on the localhost address 127.0.0.1, +which means it will not be reachable from outside of this system.

+

In order to use a random port assignment, you can use the port 0:

+
$server = new TcpServer(0, $loop);
+$address = $server->getAddress();
+

In order to change the host the socket is listening on, you can provide an IP +address through the first parameter provided to the constructor, optionally +preceded by the tcp:// scheme:

+
$server = new TcpServer('192.168.0.1:8080', $loop);
+

If you want to listen on an IPv6 address, you MUST enclose the host in square +brackets:

+
$server = new TcpServer('[::1]:8080', $loop);
+

If the given URI is invalid, does not contain a port, any other scheme or if it +contains a hostname, it will throw an InvalidArgumentException:

+
// throws InvalidArgumentException due to missing port
+$server = new TcpServer('127.0.0.1', $loop);
+

If the given URI appears to be valid, but listening on it fails (such as if port +is already in use or port below 1024 may require root access etc.), it will +throw a RuntimeException:

+
$first = new TcpServer(8080, $loop);
+
+// throws RuntimeException because port is already in use
+$second = new TcpServer(8080, $loop);
+
+

Note that these error conditions may vary depending on your system and/or +configuration. +See the exception message and code for more details about the actual error +condition.

+
+

Optionally, you can specify socket context options +for the underlying stream socket resource like this:

+
$server = new TcpServer('[::1]:8080', $loop, array(
+    'backlog' => 200,
+    'so_reuseport' => true,
+    'ipv6_v6only' => true
+));
+
+

Note that available socket context options, +their defaults and effects of changing these may vary depending on your system +and/or PHP version. +Passing unknown context options has no effect.

+
+

Whenever a client connects, it will emit a connection event with a connection +instance implementing ConnectionInterface:

+
$server->on('connection', function (ConnectionInterface $connection) {
+    echo 'Plaintext connection from ' . $connection->getRemoteAddress() . PHP_EOL;
+    
+    $connection->write('hello there!' . PHP_EOL);
+
+});
+

See also the ServerInterface for more details.

+

+SecureServer

+

The SecureServer class implements the ServerInterface +and is responsible for providing a secure TLS (formerly known as SSL) server.

+

It does so by wrapping a TcpServer instance which waits for plaintext +TCP/IP connections and then performs a TLS handshake for each connection. +It thus requires valid TLS context options, +which in its most basic form may look something like this if you're using a +PEM encoded certificate file:

+
$server = new TcpServer(8000, $loop);
+$server = new SecureServer($server, $loop, array(
+    'local_cert' => 'server.pem'
+));
+
+

Note that the certificate file will not be loaded on instantiation but when an +incoming connection initializes its TLS context. +This implies that any invalid certificate file paths or contents will only cause +an error event at a later time.

+
+

If your private key is encrypted with a passphrase, you have to specify it +like this:

+
$server = new TcpServer(8000, $loop);
+$server = new SecureServer($server, $loop, array(
+    'local_cert' => 'server.pem',
+    'passphrase' => 'secret'
+));
+

By default, this server supports TLSv1.0+ and excludes support for legacy +SSLv2/SSLv3. As of PHP 5.6+ you can also explicitly choose the TLS version you +want to negotiate with the remote side:

+
$server = new TcpServer(8000, $loop);
+$server = new SecureServer($server, $loop, array(
+    'local_cert' => 'server.pem',
+    'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_SERVER
+));
+
+

Note that available TLS context options, +their defaults and effects of changing these may vary depending on your system +and/or PHP version. +Passing unknown context options has no effect.

+
+

Whenever a client completes the TLS handshake, it will emit a connection event +with a connection instance implementing ConnectionInterface:

+
$server->on('connection', function (ConnectionInterface $connection) {
+    echo 'Secure connection from' . $connection->getRemoteAddress() . PHP_EOL;
+    
+    $connection->write('hello there!' . PHP_EOL);
+
+});
+

Whenever a client fails to perform a successful TLS handshake, it will emit an +error event and then close the underlying TCP/IP connection:

+
$server->on('error', function (Exception $e) {
+    echo 'Error' . $e->getMessage() . PHP_EOL;
+});
+

See also the ServerInterface for more details.

+

Note that the SecureServer class is a concrete implementation for TLS sockets. +If you want to typehint in your higher-level protocol implementation, you SHOULD +use the generic ServerInterface instead.

+
+

Advanced usage: Despite allowing any ServerInterface as first parameter, +you SHOULD pass a TcpServer instance as first parameter, unless you +know what you're doing. +Internally, the SecureServer has to set the required TLS context options on +the underlying stream resources. +These resources are not exposed through any of the interfaces defined in this +package, but only through the internal Connection class. +The TcpServer class is guaranteed to emit connections that implement +the ConnectionInterface and uses the internal Connection class in order to +expose these underlying resources. +If you use a custom ServerInterface and its connection event does not +meet this requirement, the SecureServer will emit an error event and +then close the underlying connection.

+
+

+UnixServer

+

The UnixServer class implements the ServerInterface and +is responsible for accepting connections on Unix domain sockets (UDS).

+
$server = new UnixServer('/tmp/server.sock', $loop);
+

As above, the $uri parameter can consist of only a socket path or socket path +prefixed by the unix:// scheme.

+

If the given URI appears to be valid, but listening on it fails (such as if the +socket is already in use or the file not accessible etc.), it will throw a +RuntimeException:

+
$first = new UnixServer('/tmp/same.sock', $loop);
+
+// throws RuntimeException because socket is already in use
+$second = new UnixServer('/tmp/same.sock', $loop);
+

Whenever a client connects, it will emit a connection event with a connection +instance implementing ConnectionInterface:

+
$server->on('connection', function (ConnectionInterface $connection) {
+    echo 'New connection' . PHP_EOL;
+
+    $connection->write('hello there!' . PHP_EOL);
+
+});
+

See also the ServerInterface for more details.

+

+LimitingServer

+

The LimitingServer decorator wraps a given ServerInterface and is responsible +for limiting and keeping track of open connections to this server instance.

+

Whenever the underlying server emits a connection event, it will check its +limits and then either

+
    +
  • keep track of this connection by adding it to the list of +open connections and then forward the connection event
  • +
  • or reject (close) the connection when its limits are exceeded and will +forward an error event instead.
  • +
+

Whenever a connection closes, it will remove this connection from the list of +open connections.

+
$server = new LimitingServer($server, 100);
+$server->on('connection', function (ConnectionInterface $connection) {
+    $connection->write('hello there!' . PHP_EOL);
+
+});
+

See also the second example for more details.

+

You have to pass a maximum number of open connections to ensure +the server will automatically reject (close) connections once this limit +is exceeded. In this case, it will emit an error event to inform about +this and no connection event will be emitted.

+
$server = new LimitingServer($server, 100);
+$server->on('connection', function (ConnectionInterface $connection) {
+    $connection->write('hello there!' . PHP_EOL);
+
+});
+

You MAY pass a null limit in order to put no limit on the number of +open connections and keep accepting new connection until you run out of +operating system resources (such as open file handles). This may be +useful if you do not want to take care of applying a limit but still want +to use the getConnections() method.

+

You can optionally configure the server to pause accepting new +connections once the connection limit is reached. In this case, it will +pause the underlying server and no longer process any new connections at +all, thus also no longer closing any excessive connections. +The underlying operating system is responsible for keeping a backlog of +pending connections until its limit is reached, at which point it will +start rejecting further connections. +Once the server is below the connection limit, it will continue consuming +connections from the backlog and will process any outstanding data on +each connection. +This mode may be useful for some protocols that are designed to wait for +a response message (such as HTTP), but may be less useful for other +protocols that demand immediate responses (such as a "welcome" message in +an interactive chat).

+
$server = new LimitingServer($server, 100, true);
+$server->on('connection', function (ConnectionInterface $connection) {
+    $connection->write('hello there!' . PHP_EOL);
+
+});
+
+getConnections()
+

The getConnections(): ConnectionInterface[] method can be used to +return an array with all currently active connections.

+
foreach ($server->getConnection() as $connection) {
+    $connection->write('Hi!');
+}
+

+Client usage

+

+ConnectorInterface

+

The ConnectorInterface is responsible for providing an interface for +establishing streaming connections, such as a normal TCP/IP connection.

+

This is the main interface defined in this package and it is used throughout +React's vast ecosystem.

+

Most higher-level components (such as HTTP, database or other networking +service clients) accept an instance implementing this interface to create their +TCP/IP connection to the underlying networking service. +This is usually done via dependency injection, so it's fairly simple to actually +swap this implementation against any other implementation of this interface.

+

The interface only offers a single method:

+

+connect()

+

The connect(string $uri): PromiseInterface<ConnectionInterface, Exception> method +can be used to create a streaming connection to the given remote address.

+

It returns a Promise which either +fulfills with a stream implementing ConnectionInterface +on success or rejects with an Exception if the connection is not successful:

+
$connector->connect('google.com:443')->then(
+    function (ConnectionInterface $connection) {
+        // connection successfully established
+    },
+    function (Exception $error) {
+        // failed to connect due to $error
+    }
+);
+

See also ConnectionInterface for more details.

+

The returned Promise MUST be implemented in such a way that it can be +cancelled when it is still pending. Cancelling a pending promise MUST +reject its value with an Exception. It SHOULD clean up any underlying +resources and references as applicable:

+
$promise = $connector->connect($uri);
+
+$promise->cancel();
+

+Connector

+

The Connector class is the main class in this package that implements the +ConnectorInterface and allows you to create streaming connections.

+

You can use this connector to create any kind of streaming connections, such +as plaintext TCP/IP, secure TLS or local Unix connection streams.

+

It binds to the main event loop and can be used like this:

+
$loop = React\EventLoop\Factory::create();
+$connector = new Connector($loop);
+
+$connector->connect($uri)->then(function (ConnectionInterface $connection) {
+    $connection->write('...');
+    $connection->end();
+});
+
+$loop->run();
+

In order to create a plaintext TCP/IP connection, you can simply pass a host +and port combination like this:

+
$connector->connect('www.google.com:80')->then(function (ConnectionInterface $connection) {
+    $connection->write('...');
+    $connection->end();
+});
+
+

If you do no specify a URI scheme in the destination URI, it will assume +tcp:// as a default and establish a plaintext TCP/IP connection. +Note that TCP/IP connections require a host and port part in the destination +URI like above, all other URI components are optional.

+
+

In order to create a secure TLS connection, you can use the tls:// URI scheme +like this:

+
$connector->connect('tls://www.google.com:443')->then(function (ConnectionInterface $connection) {
+    $connection->write('...');
+    $connection->end();
+});
+

In order to create a local Unix domain socket connection, you can use the +unix:// URI scheme like this:

+
$connector->connect('unix:///tmp/demo.sock')->then(function (ConnectionInterface $connection) {
+    $connection->write('...');
+    $connection->end();
+});
+
+

The getRemoteAddress() method will return the target +Unix domain socket (UDS) path as given to the connect() method, including +the unix:// scheme, for example unix:///tmp/demo.sock. +The getLocalAddress() method will most likely return a +null value as this value is not applicable to UDS connections here.

+
+

Under the hood, the Connector is implemented as a higher-level facade +for the lower-level connectors implemented in this package. This means it +also shares all of their features and implementation details. +If you want to typehint in your higher-level protocol implementation, you SHOULD +use the generic ConnectorInterface instead.

+

The Connector class will try to detect your system DNS settings (and uses +Google's public DNS server 8.8.8.8 as a fallback if unable to determine your +system settings) to resolve all public hostnames into underlying IP addresses by +default. +If you explicitly want to use a custom DNS server (such as a local DNS relay or +a company wide DNS server), you can set up the Connector like this:

+
$connector = new Connector($loop, array(
+    'dns' => '127.0.1.1'
+));
+
+$connector->connect('localhost:80')->then(function (ConnectionInterface $connection) {
+    $connection->write('...');
+    $connection->end();
+});
+

If you do not want to use a DNS resolver at all and want to connect to IP +addresses only, you can also set up your Connector like this:

+
$connector = new Connector($loop, array(
+    'dns' => false
+));
+
+$connector->connect('127.0.0.1:80')->then(function (ConnectionInterface $connection) {
+    $connection->write('...');
+    $connection->end();
+});
+

Advanced: If you need a custom DNS Resolver instance, you can also set up +your Connector like this:

+
$dnsResolverFactory = new React\Dns\Resolver\Factory();
+$resolver = $dnsResolverFactory->createCached('127.0.1.1', $loop);
+
+$connector = new Connector($loop, array(
+    'dns' => $resolver
+));
+
+$connector->connect('localhost:80')->then(function (ConnectionInterface $connection) {
+    $connection->write('...');
+    $connection->end();
+});
+

By default, the tcp:// and tls:// URI schemes will use timeout value that +repects your default_socket_timeout ini setting (which defaults to 60s). +If you want a custom timeout value, you can simply pass this like this:

+
$connector = new Connector($loop, array(
+    'timeout' => 10.0
+));
+

Similarly, if you do not want to apply a timeout at all and let the operating +system handle this, you can pass a boolean flag like this:

+
$connector = new Connector($loop, array(
+    'timeout' => false
+));
+

By default, the Connector supports the tcp://, tls:// and unix:// +URI schemes. If you want to explicitly prohibit any of these, you can simply +pass boolean flags like this:

+
// only allow secure TLS connections
+$connector = new Connector($loop, array(
+    'tcp' => false,
+    'tls' => true,
+    'unix' => false,
+));
+
+$connector->connect('tls://google.com:443')->then(function (ConnectionInterface $connection) {
+    $connection->write('...');
+    $connection->end();
+});
+

The tcp:// and tls:// also accept additional context options passed to +the underlying connectors. +If you want to explicitly pass additional context options, you can simply +pass arrays of context options like this:

+
// allow insecure TLS connections
+$connector = new Connector($loop, array(
+    'tcp' => array(
+        'bindto' => '192.168.0.1:0'
+    ),
+    'tls' => array(
+        'verify_peer' => false,
+        'verify_peer_name' => false
+    ),
+));
+
+$connector->connect('tls://localhost:443')->then(function (ConnectionInterface $connection) {
+    $connection->write('...');
+    $connection->end();
+});
+

By default, this connector supports TLSv1.0+ and excludes support for legacy +SSLv2/SSLv3. As of PHP 5.6+ you can also explicitly choose the TLS version you +want to negotiate with the remote side:

+
$connector = new Connector($loop, array(
+    'tls' => array(
+        'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
+    )
+));
+
+

For more details about context options, please refer to the PHP documentation +about socket context options +and SSL context options.

+
+

Advanced: By default, the Connector supports the tcp://, tls:// and +unix:// URI schemes. +For this, it sets up the required connector classes automatically. +If you want to explicitly pass custom connectors for any of these, you can simply +pass an instance implementing the ConnectorInterface like this:

+
$dnsResolverFactory = new React\Dns\Resolver\Factory();
+$resolver = $dnsResolverFactory->createCached('127.0.1.1', $loop);
+$tcp = new DnsConnector(new TcpConnector($loop), $resolver);
+
+$tls = new SecureConnector($tcp, $loop);
+
+$unix = new UnixConnector($loop);
+
+$connector = new Connector($loop, array(
+    'tcp' => $tcp,
+    'tls' => $tls,
+    'unix' => $unix,
+
+    'dns' => false,
+    'timeout' => false,
+));
+
+$connector->connect('google.com:80')->then(function (ConnectionInterface $connection) {
+    $connection->write('...');
+    $connection->end();
+});
+
+

Internally, the tcp:// connector will always be wrapped by the DNS resolver, +unless you disable DNS like in the above example. In this case, the tcp:// +connector receives the actual hostname instead of only the resolved IP address +and is thus responsible for performing the lookup. +Internally, the automatically created tls:// connector will always wrap the +underlying tcp:// connector for establishing the underlying plaintext +TCP/IP connection before enabling secure TLS mode. If you want to use a custom +underlying tcp:// connector for secure TLS connections only, you may +explicitly pass a tls:// connector like above instead. +Internally, the tcp:// and tls:// connectors will always be wrapped by +TimeoutConnector, unless you disable timeouts like in the above example.

+
+

+Advanced client usage

+

+TcpConnector

+

The React\Socket\TcpConnector class implements the +ConnectorInterface and allows you to create plaintext +TCP/IP connections to any IP-port-combination:

+
$tcpConnector = new React\Socket\TcpConnector($loop);
+
+$tcpConnector->connect('127.0.0.1:80')->then(function (ConnectionInterface $connection) {
+    $connection->write('...');
+    $connection->end();
+});
+
+$loop->run();
+

See also the examples.

+

Pending connection attempts can be cancelled by cancelling its pending promise like so:

+
$promise = $tcpConnector->connect('127.0.0.1:80');
+
+$promise->cancel();
+

Calling cancel() on a pending promise will close the underlying socket +resource, thus cancelling the pending TCP/IP connection, and reject the +resulting promise.

+

You can optionally pass additional +socket context options +to the constructor like this:

+
$tcpConnector = new React\Socket\TcpConnector($loop, array(
+    'bindto' => '192.168.0.1:0'
+));
+

Note that this class only allows you to connect to IP-port-combinations. +If the given URI is invalid, does not contain a valid IP address and port +or contains any other scheme, it will reject with an +InvalidArgumentException:

+

If the given URI appears to be valid, but connecting to it fails (such as if +the remote host rejects the connection etc.), it will reject with a +RuntimeException.

+

If you want to connect to hostname-port-combinations, see also the following chapter.

+
+

Advanced usage: Internally, the TcpConnector allocates an empty context +resource for each stream resource. +If the destination URI contains a hostname query parameter, its value will +be used to set up the TLS peer name. +This is used by the SecureConnector and DnsConnector to verify the peer +name and can also be used if you want a custom TLS peer name.

+
+

+DnsConnector

+

The DnsConnector class implements the +ConnectorInterface and allows you to create plaintext +TCP/IP connections to any hostname-port-combination.

+

It does so by decorating a given TcpConnector instance so that it first +looks up the given domain name via DNS (if applicable) and then establishes the +underlying TCP/IP connection to the resolved target IP address.

+

Make sure to set up your DNS resolver and underlying TCP connector like this:

+
$dnsResolverFactory = new React\Dns\Resolver\Factory();
+$dns = $dnsResolverFactory->createCached('8.8.8.8', $loop);
+
+$dnsConnector = new React\Socket\DnsConnector($tcpConnector, $dns);
+
+$dnsConnector->connect('www.google.com:80')->then(function (ConnectionInterface $connection) {
+    $connection->write('...');
+    $connection->end();
+});
+
+$loop->run();
+

See also the examples.

+

Pending connection attempts can be cancelled by cancelling its pending promise like so:

+
$promise = $dnsConnector->connect('www.google.com:80');
+
+$promise->cancel();
+

Calling cancel() on a pending promise will cancel the underlying DNS lookup +and/or the underlying TCP/IP connection and reject the resulting promise.

+
+

Advanced usage: Internally, the DnsConnector relies on a Resolver to +look up the IP address for the given hostname. +It will then replace the hostname in the destination URI with this IP and +append a hostname query parameter and pass this updated URI to the underlying +connector. +The underlying connector is thus responsible for creating a connection to the +target IP address, while this query parameter can be used to check the original +hostname and is used by the TcpConnector to set up the TLS peer name. +If a hostname is given explicitly, this query parameter will not be modified, +which can be useful if you want a custom TLS peer name.

+
+

+SecureConnector

+

The SecureConnector class implements the +ConnectorInterface and allows you to create secure +TLS (formerly known as SSL) connections to any hostname-port-combination.

+

It does so by decorating a given DnsConnector instance so that it first +creates a plaintext TCP/IP connection and then enables TLS encryption on this +stream.

+
$secureConnector = new React\Socket\SecureConnector($dnsConnector, $loop);
+
+$secureConnector->connect('www.google.com:443')->then(function (ConnectionInterface $connection) {
+    $connection->write("GET / HTTP/1.0\r\nHost: www.google.com\r\n\r\n");
+    ...
+});
+
+$loop->run();
+

See also the examples.

+

Pending connection attempts can be cancelled by cancelling its pending promise like so:

+
$promise = $secureConnector->connect('www.google.com:443');
+
+$promise->cancel();
+

Calling cancel() on a pending promise will cancel the underlying TCP/IP +connection and/or the SSL/TLS negotiation and reject the resulting promise.

+

You can optionally pass additional +SSL context options +to the constructor like this:

+
$secureConnector = new React\Socket\SecureConnector($dnsConnector, $loop, array(
+    'verify_peer' => false,
+    'verify_peer_name' => false
+));
+

By default, this connector supports TLSv1.0+ and excludes support for legacy +SSLv2/SSLv3. As of PHP 5.6+ you can also explicitly choose the TLS version you +want to negotiate with the remote side:

+
$secureConnector = new React\Socket\SecureConnector($dnsConnector, $loop, array(
+    'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
+));
+
+

Advanced usage: Internally, the SecureConnector relies on setting up the +required context options on the underlying stream resource. +It should therefor be used with a TcpConnector somewhere in the connector +stack so that it can allocate an empty context resource for each stream +resource and verify the peer name. +Failing to do so may result in a TLS peer name mismatch error or some hard to +trace race conditions, because all stream resources will use a single, shared +default context resource otherwise.

+
+

+TimeoutConnector

+

The TimeoutConnector class implements the +ConnectorInterface and allows you to add timeout +handling to any existing connector instance.

+

It does so by decorating any given ConnectorInterface +instance and starting a timer that will automatically reject and abort any +underlying connection attempt if it takes too long.

+
$timeoutConnector = new React\Socket\TimeoutConnector($connector, 3.0, $loop);
+
+$timeoutConnector->connect('google.com:80')->then(function (ConnectionInterface $connection) {
+    // connection succeeded within 3.0 seconds
+});
+

See also any of the examples.

+

Pending connection attempts can be cancelled by cancelling its pending promise like so:

+
$promise = $timeoutConnector->connect('google.com:80');
+
+$promise->cancel();
+

Calling cancel() on a pending promise will cancel the underlying connection +attempt, abort the timer and reject the resulting promise.

+

+UnixConnector

+

The UnixConnector class implements the +ConnectorInterface and allows you to connect to +Unix domain socket (UDS) paths like this:

+
$connector = new React\Socket\UnixConnector($loop);
+
+$connector->connect('/tmp/demo.sock')->then(function (ConnectionInterface $connection) {
+    $connection->write("HELLO\n");
+});
+
+$loop->run();
+

Connecting to Unix domain sockets is an atomic operation, i.e. its promise will +settle (either resolve or reject) immediately. +As such, calling cancel() on the resulting promise has no effect.

+
+

The getRemoteAddress() method will return the target +Unix domain socket (UDS) path as given to the connect() method, prepended +with the unix:// scheme, for example unix:///tmp/demo.sock. +The getLocalAddress() method will most likely return a +null value as this value is not applicable to UDS connections here.

+
+

+FixedUriConnector

+

The FixedUriConnector class implements the +ConnectorInterface and decorates an existing Connector +to always use a fixed, preconfigured URI.

+

This can be useful for consumers that do not support certain URIs, such as +when you want to explicitly connect to a Unix domain socket (UDS) path +instead of connecting to a default address assumed by an higher-level API:

+
$connector = new FixedUriConnector(
+    'unix:///var/run/docker.sock',
+    new UnixConnector($loop)
+);
+
+// destination will be ignored, actually connects to Unix domain socket
+$promise = $connector->connect('localhost:80');
+

+Install

+

The recommended way to install this library is through Composer. +New to Composer?

+

This will install the latest supported version:

+
$ composer require react/socket:^0.8.12
+

See also the CHANGELOG for details about version upgrades.

+

This project aims to run on any platform and thus does not require any PHP +extensions and supports running on legacy PHP 5.3 through current PHP 7+ and HHVM. +It's highly recommended to use PHP 7+ for this project, partly due to its vast +performance improvements and partly because legacy PHP versions require several +workarounds as described below.

+

Secure TLS connections received some major upgrades starting with PHP 5.6, with +the defaults now being more secure, while older versions required explicit +context options. +This library does not take responsibility over these context options, so it's +up to consumers of this library to take care of setting appropriate context +options as described above.

+

All versions of PHP prior to 5.6.8 suffered from a buffering issue where reading +from a streaming TLS connection could be one data event behind. +This library implements a work-around to try to flush the complete incoming +data buffers on these legacy PHP versions, which has a penalty of around 10% of +throughput on all connections. +With this work-around, we have not been able to reproduce this issue anymore, +but we have seen reports of people saying this could still affect some of the +older PHP versions (5.5.23, 5.6.7, and 5.6.8). +Note that this only affects some higher-level streaming protocols, such as +IRC over TLS, but should not affect HTTP over TLS (HTTPS). +Further investigation of this issue is needed. +For more insights, this issue is also covered by our test suite.

+

PHP < 7.1.4 (and PHP < 7.0.18) suffers from a bug when writing big +chunks of data over TLS streams at once. +We try to work around this by limiting the write chunk size to 8192 +bytes for older PHP versions only. +This is only a work-around and has a noticable performance penalty on +affected versions.

+

This project also supports running on HHVM. +Note that really old HHVM < 3.8 does not support secure TLS connections, as it +lacks the required stream_socket_enable_crypto() function. +As such, trying to create a secure TLS connections on affected versions will +return a rejected promise instead. +This issue is also covered by our test suite, which will skip related tests +on affected versions.

+

+Tests

+

To run the test suite, you first need to clone this repo and then install all +dependencies through Composer:

+
$ composer install
+

To run the test suite, go to the project root and run:

+
$ php vendor/bin/phpunit
+

The test suite also contains a number of functional integration tests that rely +on a stable internet connection. +If you do not want to run these, they can simply be skipped like this:

+
$ php vendor/bin/phpunit --exclude-group internet
+

+License

+

MIT, see LICENSE file.

+
+ +
+
+
+ + + + + + diff --git a/socket/license.html b/socket/license.html new file mode 100644 index 000000000..58de6f2c4 --- /dev/null +++ b/socket/license.html @@ -0,0 +1,612 @@ + + + + + + + + Socket: License - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

Socket License

+ +

Copyright (c) 2012 Igor Wiedler, Chris Boden

+

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions:

+

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.

+
+ +
+
+
+ + + + + + diff --git a/stream/changelog.html b/stream/changelog.html new file mode 100644 index 000000000..175c7f73b --- /dev/null +++ b/stream/changelog.html @@ -0,0 +1,1441 @@ + + + + + + + + Stream: Changelog - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

Stream Changelog

+ + + +

+ + 2018 +

+ + +

+ + + 0.7.7 + + + (2018-01-19) + + Release on GitHub + + +

+ +
    +
  • Improve test suite by fixing forward compatibility with upcoming EventLoop
    +releases, avoid risky tests and add test group to skip integration tests
    +relying on internet connection and apply appropriate test timeouts.
    +(#128, #131 and #132 by @clue)
  • +
+ +
+

+ + 2017 +

+ + +

+ + + 0.7.6 + + + (2017-12-21) + + Release on GitHub + + +

+ +
    +
  • +

    Fix: Work around reading from unbuffered pipe stream in legacy PHP < 5.4.28 and PHP < 5.5.12
    +(#126 by @clue)

    +
  • +
  • +

    Improve test suite by simplifying test bootstrapping logic via Composer and
    +test against PHP 7.2
    +(#127 by @clue and #124 by @carusogabriel)

    +
  • +
+ +
+ +

+ + + 0.7.5 + + + (2017-11-20) + + Release on GitHub + + +

+ +
    +
  • +

    Fix: Igore excessive fopen() mode flags for WritableResourceStream
    +(#119 by @clue)

    +
  • +
  • +

    Fix: Fix forward compatibility with upcoming EventLoop releases
    +(#121 by @clue)

    +
  • +
  • +

    Restructure examples to ease getting started
    +(#123 by @clue)

    +
  • +
  • +

    Improve test suite by adding forward compatibility with PHPUnit 6 and
    +ignore Mac OS X test failures for now until Travis tests work again
    +(#122 by @gabriel-caruso and #120 by @clue)

    +
  • +
+ +
+ +

+ + + 0.7.4 + + + (2017-10-11) + + Release on GitHub + + +

+ +
    +
  • +

    Fix: Remove event listeners from CompositeStream once closed and
    +remove undocumented left-over close event argument
    +(#116 by @clue)

    +
  • +
  • +

    Minor documentation improvements: Fix wrong class name in example,
    +fix typos in README and
    +fix forward compatibility with upcoming EventLoop releases in example
    +(#113 by @docteurklein and #114 and #115 by @clue)

    +
  • +
  • +

    Improve test suite by running against Mac OS X on Travis
    +(#112 by @clue)

    +
  • +
+ +
+ +

+ + + 0.7.3 + + + (2017-08-05) + + Release on GitHub + + +

+ +
    +
  • Improvement: Support Événement 3.0 a long side 2.0 and 1.0
    +(#108 by @WyriHaximus)
  • +
  • Readme: Corrected loop initialization in usage example
    +(#109 by @pulyavin)
  • +
  • Travis: Lock linux distribution preventing future builds from breaking
    +(#110 by @clue)
  • +
+ +
+ +

+ + + 0.7.2 + + + (2017-06-15) + + Release on GitHub + + +

+ +
    +
  • Bug fix: WritableResourceStream: Close the underlying stream when closing the stream.
    +(#107 by @WyriHaximus)
  • +
+ +
+ +

+ + + 0.7.1 + + + (2017-05-20) + + Release on GitHub + + +

+ +
    +
  • +

    Feature: Add optional $writeChunkSize parameter to limit maximum number of
    +bytes to write at once.
    +(#105 by @clue)

    +
    $stream = new WritableResourceStream(STDOUT, $loop, null, 8192);
    +
  • +
  • +

    Ignore HHVM test failures for now until Travis tests work again
    +(#106 by @clue)

    +
  • +
+ +
+ +

+ + + 0.7.0 + + + (2017-05-04) + + Release on GitHub + + +

+ +
    +
  • +

    Removed / BC break: Remove deprecated and unneeded functionality
    +(#45, #87, #90, #91 and #93 by @clue)

    +
      +
    • +

      Remove deprecated Stream class, use DuplexResourceStream instead
      +(#87 by @clue)

      +
    • +
    • +

      Remove public $buffer property, use new constructor parameters instead
      +(#91 by @clue)

      +
    • +
    • +

      Remove public $stream property from all resource streams
      +(#90 by @clue)

      +
    • +
    • +

      Remove undocumented and now unused ReadableStream and WritableStream
      +(#93 by @clue)

      +
    • +
    • +

      Remove BufferedSink
      +(#45 by @clue)

      +
    • +
    +
  • +
  • +

    Feature / BC break: Simplify ThroughStream by using data callback instead of
    +inheritance. It is now a direct implementation of DuplexStreamInterface.
    +(#88 and #89 by @clue)

    +
    $through = new ThroughStream(function ($data) {
    +    return json_encode($data) . PHP_EOL;
    +});
    +$through->on('data', $this->expectCallableOnceWith("[2, true]\n"));
    +
    +$through->write(array(2, true));
    +
  • +
  • +

    Feature / BC break: The CompositeStream starts closed if either side is
    +already closed and forwards pause to pipe source on first write attempt.
    +(#96 and #103 by @clue)

    +

    If either side of the composite stream closes, it will also close the other
    +side. We now also ensure that if either side is already closed during
    +instantiation, it will also close the other side.

    +
  • +
  • +

    BC break: Mark all classes as final and
    +mark internal API as private to discourage inheritance
    +(#95 and #99 by @clue)

    +
  • +
  • +

    Feature / BC break: Only emit error event for fatal errors
    +(#92 by @clue)

    +
    +

    The error event was previously also allowed to be emitted for non-fatal
    +errors, but our implementations actually only ever emitted this as a fatal
    +error and then closed the stream.

    +
    +
  • +
  • +

    Feature: Explicitly allow custom events and exclude any semantics
    +(#97 by @clue)

    +
  • +
  • +

    Support legacy PHP 5.3 through PHP 7.1 and HHVM and improve usage documentation
    +(#100 and #102 by @clue)

    +
  • +
  • +

    Actually require all dependencies so this is self-contained and improve
    +forward compatibility with EventLoop v1.0 and v0.5
    +(#94 and #98 by @clue)

    +
  • +
+ +
+ +

+ + + 0.6.0 + + + (2017-03-26) + + Release on GitHub + + +

+ +
    +
  • +

    Feature / Fix / BC break: Add DuplexResourceStream and deprecate Stream
    +(#85 by @clue)

    +
    // old (does still work for BC reasons)
    +$stream = new Stream($connection, $loop);
    +
    +// new
    +$stream = new DuplexResourceStream($connection, $loop);
    +

    Note that the DuplexResourceStream now rejects read-only or write-only
    +streams, so this may affect BC. If you want a read-only or write-only
    +resource, use ReadableResourceStream or WritableResourceStream instead of
    +DuplexResourceStream.

    +
    +

    BC note: This class was previously called Stream. The Stream class still
    +exists for BC reasons and will be removed in future versions of this package.

    +
    +
  • +
  • +

    Feature / BC break: Add WritableResourceStream (previously called Buffer)
    +(#84 by @clue)

    +
    // old
    +$stream = new Buffer(STDOUT, $loop);
    +
    +// new
    +$stream = new WritableResourceStream(STDOUT, $loop);
    +
  • +
  • +

    Feature: Add ReadableResourceStream
    +(#83 by @clue)

    +
    $stream = new ReadableResourceStream(STDIN, $loop);
    +
  • +
  • +

    Fix / BC Break: Enforce using non-blocking I/O
    +(#46 by @clue)

    +
    +

    BC note: This is known to affect process pipes on Windows which do not
    +support non-blocking I/O and could thus block the whole EventLoop previously.

    +
    +
  • +
  • +

    Feature / Fix / BC break: Consistent semantics for
    +DuplexStreamInterface::end() to ensure it SHOULD also end readable side
    +(#86 by @clue)

    +
  • +
  • +

    Fix: Do not use unbuffered reads on pipe streams for legacy PHP < 5.4
    +(#80 by @clue)

    +
  • +
+ +
+ +

+ + + 0.5.0 + + + (2017-03-08) + + Release on GitHub + + +

+ +
    +
  • +

    Feature / BC break: Consistent end event semantics (EOF)
    +(#70 by @clue)

    +

    The end event will now only be emitted for a successful end, not if the
    +stream closes due to an unrecoverable error event or if you call close()
    +explicitly.
    +If you want to detect when the stream closes (terminates), use the close
    +event instead.

    +
  • +
  • +

    BC break: Remove custom (undocumented) full-drain event from Buffer
    +(#63 and #68 by @clue)

    +
    +

    The full-drain event was undocumented and mostly used internally.
    +Relying on this event has attracted some low-quality code in the past, so
    +we've removed this from the public API in order to work out a better
    +solution instead.
    +If you want to detect when the buffer finishes flushing data to the stream,
    +you may want to look into its end() method or the close event instead.

    +
    +
  • +
  • +

    Feature / BC break: Consistent event semantics and documentation,
    +explicitly state when events will be emitted and which arguments they
    +receive.
    +(#73 and #69 by @clue)

    +

    The documentation now explicitly defines each event and its arguments.
    +Custom events and event arguments are still supported.
    +Most notably, all defined events only receive inherently required event
    +arguments and no longer transmit the instance they are emitted on for
    +consistency and performance reasons.

    +
    // old (inconsistent and not supported by all implementations)
    +$stream->on('data', function ($data, $stream) {
    +    // process $data
    +});
    +
    +// new (consistent throughout the whole ecosystem)
    +$stream->on('data', function ($data) use ($stream) {
    +    // process $data
    +});
    +
    +

    This mostly adds documentation (and thus some stricter, consistent
    +definitions) for the existing behavior, it does NOT define any major
    +changes otherwise.
    +Most existing code should be compatible with these changes, unless
    +it relied on some undocumented/unintended semantics.

    +
    +
  • +
  • +

    Feature / BC break: Consistent method semantics and documentation
    +(#72 by @clue)

    +
    +

    This mostly adds documentation (and thus some stricter, consistent
    +definitions) for the existing behavior, it does NOT define any major
    +changes otherwise.
    +Most existing code should be compatible with these changes, unless
    +it relied on some undocumented/unintended semantics.

    +
    +
  • +
  • +

    Feature: Consistent pipe() semantics for closed and closing streams
    +(#71 from @clue)

    +

    The source stream will now always be paused via pause() when the
    +destination stream closes. Also, properly stop piping if the source
    +stream closes and remove all event forwarding.

    +
  • +
  • +

    Improve test suite by adding PHPUnit to require-dev and improving coverage.
    +(#74 and #75 by @clue, #66 by @nawarian)

    +
  • +
+ +
+ +

+ + + 0.4.6 + + + (2017-01-25) + + Release on GitHub + + +

+ +
    +
  • Feature: The Buffer can now be injected into the Stream (or be used standalone)
    +(#62 by @clue)
  • +
  • Fix: Forward close event only once for CompositeStream and ThroughStream
    +(#60 by @clue)
  • +
  • Fix: Consistent close event behavior for Buffer
    +(#61 by @clue)
  • +
+ +
+

+ + 2016 +

+ + +

+ + + 0.4.5 + + + (2016-11-13) + + Release on GitHub + + +

+ +
    +
  • Feature: Support setting read buffer size to null (infinite)
    +(#42 by @clue)
  • +
  • Fix: Do not emit full-drain event if Buffer is closed during drain event
    +(#55 by @clue)
  • +
  • Vastly improved performance by factor of 10x to 20x.
    +Raise default buffer sizes to 64 KiB and simplify and improve error handling
    +and unneeded function calls.
    +(#53, #55, #56 by @clue)
  • +
+ +
+ +

+ + + 0.4.4 + + + (2016-08-22) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Emit error event and close Stream when accessing the underlying
    +stream resource fails with a permanent error.
    +(#52 and #40 by @clue, #25 by @lysenkobv)
  • +
  • Bug fix: Do not emit empty data event if nothing has been read (stream reached EOF)
    +(#39 by @clue)
  • +
  • Bug fix: Ignore empty writes to Buffer
    +(#51 by @clue)
  • +
  • Add benchmarking script to measure throughput in CI
    +(#41 by @clue)
  • +
+ +
+

+ + 2015 +

+ + +

+ + + 0.4.3 + + + (2015-10-07) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Read buffer to 0 fixes error with libevent and large quantity of I/O (@mbonneau)
  • +
  • Bug fix: No double-write during drain call (@arnaud-lb)
  • +
  • Bug fix: Support HHVM (@clue)
  • +
  • Adjust compatibility to 5.3 (@clue)
  • +
+ +
+

+ + 2014 +

+ + +

+ + + 0.4.2 + + + (2014-09-10) + + Release on GitHub + + +

+ +
    +
  • Added DuplexStreamInterface
  • +
  • Stream sets stream resources to non-blocking
  • +
  • Fixed potential race condition in pipe
  • +
+ +
+ +

+ + + 0.4.1 + + + (2014-03-30) + + Release on GitHub + + +

+ +
    +
  • Bug fix: v0.3.4 changes merged for v0.4.1
  • +
+ +
+ +

+ + + 0.3.4 + + + (2014-02-16) + + Release on GitHub + + +

+ +
    +
  • Bug fix: [Stream] Fixed 100% CPU spike from non-empty write buffer on closed stream
  • +
+ +
+ +

+ + + 0.4.0 + + + (2014-02-02) + + Release on GitHub + + +

+ +
    +
  • BC break: Bump minimum PHP version to PHP 5.4, remove 5.3 specific hacks
  • +
  • BC break: Update to Evenement 2.0
  • +
  • Dependency: Autoloading and filesystem structure now PSR-4 instead of PSR-0
  • +
+ +
+

+ + 2013 +

+ + +

+ + + 0.3.3 + + + (2013-07-09) + + Release on GitHub + + +

+ +
    +
  • Bug fix: [Stream] Correctly detect closed connections
  • +
+ +
+ +

+ + + 0.3.2 + + + (2013-05-10) + + Release on GitHub + + +

+ +
    +
  • Bug fix: [Stream] Make sure CompositeStream is closed properly
  • +
+ +
+ +

+ + + 0.3.1 + + + (2013-04-21) + + Release on GitHub + + +

+ +
    +
  • Bug fix: [Stream] Allow any ReadableStreamInterface on BufferedSink::createPromise()
  • +
+ +
+ +

+ + + 0.3.0 + + + (2013-04-14) + + Release on GitHub + + +

+ +
    +
  • Feature: [Stream] Factory method for BufferedSink
  • +
+ +
+

+ + 2012 +

+ + +

+ + + 0.2.6 + + + (2012-12-14) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + 0.2.5 + + + (2012-11-19) + + Release on GitHub + + +

+ +
    +
  • Feature: Make BufferedSink trigger progress events on the promise (@jsor)
  • +
+ +
+ +

+ + + 0.2.4 + + + (2012-11-18) + + Release on GitHub + + +

+ +
    +
  • Feature: Added ThroughStream, CompositeStream, ReadableStream and WritableStream
  • +
  • Feature: Added BufferedSink
  • +
+ +
+ +

+ + + 0.2.3 + + + (2012-11-05) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + 0.2.2 + + + (2012-10-28) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + 0.2.1 + + + (2012-10-13) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Check for EOF in Buffer::write()
  • +
+ +
+ +

+ + + 0.2.0 + + + (2012-09-10) + + Release on GitHub + + +

+ +
    +
  • Version bump
  • +
+ +
+ +

+ + + 0.1.1 + + + (2012-07-12) + + Release on GitHub + + +

+ +
    +
  • Bug fix: Testing and functional against PHP >= 5.3.3 and <= 5.3.8
  • +
+ +
+ +

+ + + 0.1.0 + + + (2012-07-11) + + Release on GitHub + + +

+ +
    +
  • First tagged release
  • +
+ +
+
+ +
+
+
+ + + + + + diff --git a/stream/index.html b/stream/index.html new file mode 100644 index 000000000..449167914 --- /dev/null +++ b/stream/index.html @@ -0,0 +1,1453 @@ + + + + + + + + Stream: +Stream - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

Stream

+ + +

Build Status

+

Event-driven readable and writable streams for non-blocking I/O in ReactPHP.

+

In order to make the EventLoop +easier to use, this component introduces the powerful concept of "streams". +Streams allow you to efficiently process huge amounts of data (such as a multi +Gigabyte file download) in small chunks without having to store everything in +memory at once. +They are very similar to the streams found in PHP itself, +but have an interface more suited for async, non-blocking I/O.

+

Table of contents

+ +

+Stream usage

+

ReactPHP uses the concept of "streams" throughout its ecosystem to provide a +consistent higher-level abstraction for processing streams of arbitrary data +contents and size. +While a stream itself is a quite low-level concept, it can be used as a powerful +abstraction to build higher-level components and protocols on top.

+

If you're new to this concept, it helps to think of them as a water pipe: +You can consume water from a source or you can produce water and forward (pipe) +it to any destination (sink).

+

Similarly, streams can either be

+
    +
  • readable (such as STDIN terminal input) or
  • +
  • writable (such as STDOUT terminal output) or
  • +
  • duplex (both readable and writable, such as a TCP/IP connection)
  • +
+

Accordingly, this package defines the following three interfaces

+ +

+ReadableStreamInterface

+

The ReadableStreamInterface is responsible for providing an interface for +read-only streams and the readable side of duplex streams.

+

Besides defining a few methods, this interface also implements the +EventEmitterInterface which allows you to react to certain events.

+

The event callback functions MUST be a valid callable that obeys strict +parameter definitions and MUST accept event parameters exactly as documented. +The event callback functions MUST NOT throw an Exception. +The return value of the event callback functions will be ignored and has no +effect, so for performance reasons you're recommended to not return any +excessive data structures.

+

Every implementation of this interface MUST follow these event semantics in +order to be considered a well-behaving stream.

+
+

Note that higher-level implementations of this interface may choose to +define additional events with dedicated semantics not defined as part of +this low-level stream specification. Conformance with these event semantics +is out of scope for this interface, so you may also have to refer to the +documentation of such a higher-level implementation.

+
+

+data event

+

The data event will be emitted whenever some data was read/received +from this source stream. +The event receives a single mixed argument for incoming data.

+
$stream->on('data', function ($data) {
+    echo $data;
+});
+

This event MAY be emitted any number of times, which may be zero times if +this stream does not send any data at all. +It SHOULD not be emitted after an end or close event.

+

The given $data argument may be of mixed type, but it's usually +recommended it SHOULD be a string value or MAY use a type that allows +representation as a string for maximum compatibility.

+

Many common streams (such as a TCP/IP connection or a file-based stream) +will emit the raw (binary) payload data that is received over the wire as +chunks of string values.

+

Due to the stream-based nature of this, the sender may send any number +of chunks with varying sizes. There are no guarantees that these chunks +will be received with the exact same framing the sender intended to send. +In other words, many lower-level protocols (such as TCP/IP) transfer the +data in chunks that may be anywhere between single-byte values to several +dozens of kilobytes. You may want to apply a higher-level protocol to +these low-level data chunks in order to achieve proper message framing.

+

+end event

+

The end event will be emitted once the source stream has successfully +reached the end of the stream (EOF).

+
$stream->on('end', function () {
+    echo 'END';
+});
+

This event SHOULD be emitted once or never at all, depending on whether +a successful end was detected. +It SHOULD NOT be emitted after a previous end or close event. +It MUST NOT be emitted if the stream closes due to a non-successful +end, such as after a previous error event.

+

After the stream is ended, it MUST switch to non-readable mode, +see also isReadable().

+

This event will only be emitted if the end was reached successfully, +not if the stream was interrupted by an unrecoverable error or explicitly +closed. Not all streams know this concept of a "successful end". +Many use-cases involve detecting when the stream closes (terminates) +instead, in this case you should use the close event. +After the stream emits an end event, it SHOULD usually be followed by a +close event.

+

Many common streams (such as a TCP/IP connection or a file-based stream) +will emit this event if either the remote side closes the connection or +a file handle was successfully read until reaching its end (EOF).

+

Note that this event should not be confused with the end() method. +This event defines a successful end reading from a source stream, while +the end() method defines writing a successful end to a destination +stream.

+

+error event

+

The error event will be emitted once a fatal error occurs, usually while +trying to read from this stream. +The event receives a single Exception argument for the error instance.

+
$server->on('error', function (Exception $e) {
+    echo 'Error: ' . $e->getMessage() . PHP_EOL;
+});
+

This event SHOULD be emitted once the stream detects a fatal error, such +as a fatal transmission error or after an unexpected data or premature +end event. +It SHOULD NOT be emitted after a previous error, end or close event. +It MUST NOT be emitted if this is not a fatal error condition, such as +a temporary network issue that did not cause any data to be lost.

+

After the stream errors, it MUST close the stream and SHOULD thus be +followed by a close event and then switch to non-readable mode, see +also close() and isReadable().

+

Many common streams (such as a TCP/IP connection or a file-based stream) +only deal with data transmission and do not make assumption about data +boundaries (such as unexpected data or premature end events). +In other words, many lower-level protocols (such as TCP/IP) may choose +to only emit this for a fatal transmission error once and will then +close (terminate) the stream in response.

+

If this stream is a DuplexStreamInterface, you should also notice +how the writable side of the stream also implements an error event. +In other words, an error may occur while either reading or writing the +stream which should result in the same error processing.

+

+close event

+

The close event will be emitted once the stream closes (terminates).

+
$stream->on('close', function () {
+    echo 'CLOSED';
+});
+

This event SHOULD be emitted once or never at all, depending on whether +the stream ever terminates. +It SHOULD NOT be emitted after a previous close event.

+

After the stream is closed, it MUST switch to non-readable mode, +see also isReadable().

+

Unlike the end event, this event SHOULD be emitted whenever the stream +closes, irrespective of whether this happens implicitly due to an +unrecoverable error or explicitly when either side closes the stream. +If you only want to detect a successful end, you should use the end +event instead.

+

Many common streams (such as a TCP/IP connection or a file-based stream) +will likely choose to emit this event after reading a successful end +event or after a fatal transmission error event.

+

If this stream is a DuplexStreamInterface, you should also notice +how the writable side of the stream also implements a close event. +In other words, after receiving this event, the stream MUST switch into +non-writable AND non-readable mode, see also isWritable(). +Note that this event should not be confused with the end event.

+

+isReadable()

+

The isReadable(): bool method can be used to +check whether this stream is in a readable state (not closed already).

+

This method can be used to check if the stream still accepts incoming +data events or if it is ended or closed already. +Once the stream is non-readable, no further data or end events SHOULD +be emitted.

+
assert($stream->isReadable() === false);
+
+$stream->on('data', assertNeverCalled());
+$stream->on('end', assertNeverCalled());
+

A successfully opened stream always MUST start in readable mode.

+

Once the stream ends or closes, it MUST switch to non-readable mode. +This can happen any time, explicitly through close() or +implicitly due to a remote close or an unrecoverable transmission error. +Once a stream has switched to non-readable mode, it MUST NOT transition +back to readable mode.

+

If this stream is a DuplexStreamInterface, you should also notice +how the writable side of the stream also implements an isWritable() +method. Unless this is a half-open duplex stream, they SHOULD usually +have the same return value.

+

+pause()

+

The pause(): void method can be used to +pause reading incoming data events.

+

Removes the data source file descriptor from the event loop. This +allows you to throttle incoming data.

+

Unless otherwise noted, a successfully opened stream SHOULD NOT start +in paused state.

+

Once the stream is paused, no futher data or end events SHOULD +be emitted.

+
$stream->pause();
+
+$stream->on('data', assertShouldNeverCalled());
+$stream->on('end', assertShouldNeverCalled());
+

This method is advisory-only, though generally not recommended, the +stream MAY continue emitting data events.

+

You can continue processing events by calling resume() again.

+

Note that both methods can be called any number of times, in particular +calling pause() more than once SHOULD NOT have any effect.

+

See also resume().

+

+resume()

+

The resume(): void method can be used to +resume reading incoming data events.

+

Re-attach the data source after a previous pause().

+
$stream->pause();
+
+$loop->addTimer(1.0, function () use ($stream) {
+    $stream->resume();
+});
+

Note that both methods can be called any number of times, in particular +calling resume() without a prior pause() SHOULD NOT have any effect.

+

See also pause().

+

+pipe()

+

The pipe(WritableStreamInterface $dest, array $options = []) method can be used to +pipe all the data from this readable source into the given writable destination.

+

Automatically sends all incoming data to the destination. +Automatically throttles the source based on what the destination can handle.

+
$source->pipe($dest);
+

Similarly, you can also pipe an instance implementing DuplexStreamInterface +into itself in order to write back all the data that is received. +This may be a useful feature for a TCP/IP echo service:

+
$connection->pipe($connection);
+

This method returns the destination stream as-is, which can be used to +set up chains of piped streams:

+
$source->pipe($decodeGzip)->pipe($filterBadWords)->pipe($dest);
+

By default, this will call end() on the destination stream once the +source stream emits an end event. This can be disabled like this:

+
$source->pipe($dest, array('end' => false));
+

Note that this only applies to the end event. +If an error or explicit close event happens on the source stream, +you'll have to manually close the destination stream:

+
$source->pipe($dest);
+$source->on('close', function () use ($dest) {
+    $dest->end('BYE!');
+});
+

If the source stream is not readable (closed state), then this is a NO-OP.

+
$source->close();
+$source->pipe($dest); // NO-OP
+

If the destinantion stream is not writable (closed state), then this will simply +throttle (pause) the source stream:

+
$dest->close();
+$source->pipe($dest); // calls $source->pause()
+

Similarly, if the destination stream is closed while the pipe is still +active, it will also throttle (pause) the source stream:

+
$source->pipe($dest);
+$dest->close(); // calls $source->pause()
+

Once the pipe is set up successfully, the destination stream MUST emit +a pipe event with this source stream an event argument.

+

+close()

+

The close(): void method can be used to +close the stream (forcefully).

+

This method can be used to (forcefully) close the stream.

+
$stream->close();
+

Once the stream is closed, it SHOULD emit a close event. +Note that this event SHOULD NOT be emitted more than once, in particular +if this method is called multiple times.

+

After calling this method, the stream MUST switch into a non-readable +mode, see also isReadable(). +This means that no further data or end events SHOULD be emitted.

+
$stream->close();
+assert($stream->isReadable() === false);
+
+$stream->on('data', assertNeverCalled());
+$stream->on('end', assertNeverCalled());
+

If this stream is a DuplexStreamInterface, you should also notice +how the writable side of the stream also implements a close() method. +In other words, after calling this method, the stream MUST switch into +non-writable AND non-readable mode, see also isWritable(). +Note that this method should not be confused with the end() method.

+

+WritableStreamInterface

+

The WritableStreamInterface is responsible for providing an interface for +write-only streams and the writable side of duplex streams.

+

Besides defining a few methods, this interface also implements the +EventEmitterInterface which allows you to react to certain events.

+

The event callback functions MUST be a valid callable that obeys strict +parameter definitions and MUST accept event parameters exactly as documented. +The event callback functions MUST NOT throw an Exception. +The return value of the event callback functions will be ignored and has no +effect, so for performance reasons you're recommended to not return any +excessive data structures.

+

Every implementation of this interface MUST follow these event semantics in +order to be considered a well-behaving stream.

+
+

Note that higher-level implementations of this interface may choose to +define additional events with dedicated semantics not defined as part of +this low-level stream specification. Conformance with these event semantics +is out of scope for this interface, so you may also have to refer to the +documentation of such a higher-level implementation.

+
+

+drain event

+

The drain event will be emitted whenever the write buffer became full +previously and is now ready to accept more data.

+
$stream->on('drain', function () use ($stream) {
+    echo 'Stream is now ready to accept more data';
+});
+

This event SHOULD be emitted once every time the buffer became full +previously and is now ready to accept more data. +In other words, this event MAY be emitted any number of times, which may +be zero times if the buffer never became full in the first place. +This event SHOULD NOT be emitted if the buffer has not become full +previously.

+

This event is mostly used internally, see also write() for more details.

+

+pipe event

+

The pipe event will be emitted whenever a readable stream is pipe()d +into this stream. +The event receives a single ReadableStreamInterface argument for the +source stream.

+
$stream->on('pipe', function (ReadableStreamInterface $source) use ($stream) {
+    echo 'Now receiving piped data';
+
+    // explicitly close target if source emits an error
+    $source->on('error', function () use ($stream) {
+        $stream->close();
+    });
+});
+
+$source->pipe($stream);
+

This event MUST be emitted once for each readable stream that is +successfully piped into this destination stream. +In other words, this event MAY be emitted any number of times, which may +be zero times if no stream is ever piped into this stream. +This event MUST NOT be emitted if either the source is not readable +(closed already) or this destination is not writable (closed already).

+

This event is mostly used internally, see also pipe() for more details.

+

+error event

+

The error event will be emitted once a fatal error occurs, usually while +trying to write to this stream. +The event receives a single Exception argument for the error instance.

+
$stream->on('error', function (Exception $e) {
+    echo 'Error: ' . $e->getMessage() . PHP_EOL;
+});
+

This event SHOULD be emitted once the stream detects a fatal error, such +as a fatal transmission error. +It SHOULD NOT be emitted after a previous error or close event. +It MUST NOT be emitted if this is not a fatal error condition, such as +a temporary network issue that did not cause any data to be lost.

+

After the stream errors, it MUST close the stream and SHOULD thus be +followed by a close event and then switch to non-writable mode, see +also close() and isWritable().

+

Many common streams (such as a TCP/IP connection or a file-based stream) +only deal with data transmission and may choose +to only emit this for a fatal transmission error once and will then +close (terminate) the stream in response.

+

If this stream is a DuplexStreamInterface, you should also notice +how the readable side of the stream also implements an error event. +In other words, an error may occur while either reading or writing the +stream which should result in the same error processing.

+

+close event

+

The close event will be emitted once the stream closes (terminates).

+
$stream->on('close', function () {
+    echo 'CLOSED';
+});
+

This event SHOULD be emitted once or never at all, depending on whether +the stream ever terminates. +It SHOULD NOT be emitted after a previous close event.

+

After the stream is closed, it MUST switch to non-writable mode, +see also isWritable().

+

This event SHOULD be emitted whenever the stream closes, irrespective of +whether this happens implicitly due to an unrecoverable error or +explicitly when either side closes the stream.

+

Many common streams (such as a TCP/IP connection or a file-based stream) +will likely choose to emit this event after flushing the buffer from +the end() method, after receiving a successful end event or after +a fatal transmission error event.

+

If this stream is a DuplexStreamInterface, you should also notice +how the readable side of the stream also implements a close event. +In other words, after receiving this event, the stream MUST switch into +non-writable AND non-readable mode, see also isReadable(). +Note that this event should not be confused with the end event.

+

+isWritable()

+

The isWritable(): bool method can be used to +check whether this stream is in a writable state (not closed already).

+

This method can be used to check if the stream still accepts writing +any data or if it is ended or closed already. +Writing any data to a non-writable stream is a NO-OP:

+
assert($stream->isWritable() === false);
+
+$stream->write('end'); // NO-OP
+$stream->end('end'); // NO-OP
+

A successfully opened stream always MUST start in writable mode.

+

Once the stream ends or closes, it MUST switch to non-writable mode. +This can happen any time, explicitly through end() or close() or +implicitly due to a remote close or an unrecoverable transmission error. +Once a stream has switched to non-writable mode, it MUST NOT transition +back to writable mode.

+

If this stream is a DuplexStreamInterface, you should also notice +how the readable side of the stream also implements an isReadable() +method. Unless this is a half-open duplex stream, they SHOULD usually +have the same return value.

+

+write()

+

The write(mixed $data): bool method can be used to +write some data into the stream.

+

A successful write MUST be confirmed with a boolean true, which means +that either the data was written (flushed) immediately or is buffered and +scheduled for a future write. Note that this interface gives you no +control over explicitly flushing the buffered data, as finding the +appropriate time for this is beyond the scope of this interface and left +up to the implementation of this interface.

+

Many common streams (such as a TCP/IP connection or file-based stream) +may choose to buffer all given data and schedule a future flush by using +an underlying EventLoop to check when the resource is actually writable.

+

If a stream cannot handle writing (or flushing) the data, it SHOULD emit +an error event and MAY close() the stream if it can not recover from +this error.

+

If the internal buffer is full after adding $data, then write() +SHOULD return false, indicating that the caller should stop sending +data until the buffer drains. +The stream SHOULD send a drain event once the buffer is ready to accept +more data.

+

Similarly, if the the stream is not writable (already in a closed state) +it MUST NOT process the given $data and SHOULD return false, +indicating that the caller should stop sending data.

+

The given $data argument MAY be of mixed type, but it's usually +recommended it SHOULD be a string value or MAY use a type that allows +representation as a string for maximum compatibility.

+

Many common streams (such as a TCP/IP connection or a file-based stream) +will only accept the raw (binary) payload data that is transferred over +the wire as chunks of string values.

+

Due to the stream-based nature of this, the sender may send any number +of chunks with varying sizes. There are no guarantees that these chunks +will be received with the exact same framing the sender intended to send. +In other words, many lower-level protocols (such as TCP/IP) transfer the +data in chunks that may be anywhere between single-byte values to several +dozens of kilobytes. You may want to apply a higher-level protocol to +these low-level data chunks in order to achieve proper message framing.

+

+end()

+

The end(mixed $data = null): void method can be used to +successfully end the stream (after optionally sending some final data).

+

This method can be used to successfully end the stream, i.e. close +the stream after sending out all data that is currently buffered.

+
$stream->write('hello');
+$stream->write('world');
+$stream->end();
+

If there's no data currently buffered and nothing to be flushed, then +this method MAY close() the stream immediately.

+

If there's still data in the buffer that needs to be flushed first, then +this method SHOULD try to write out this data and only then close() +the stream. +Once the stream is closed, it SHOULD emit a close event.

+

Note that this interface gives you no control over explicitly flushing +the buffered data, as finding the appropriate time for this is beyond the +scope of this interface and left up to the implementation of this +interface.

+

Many common streams (such as a TCP/IP connection or file-based stream) +may choose to buffer all given data and schedule a future flush by using +an underlying EventLoop to check when the resource is actually writable.

+

You can optionally pass some final data that is written to the stream +before ending the stream. If a non-null value is given as $data, then +this method will behave just like calling write($data) before ending +with no data.

+
// shorter version
+$stream->end('bye');
+
+// same as longer version
+$stream->write('bye');
+$stream->end();
+

After calling this method, the stream MUST switch into a non-writable +mode, see also isWritable(). +This means that no further writes are possible, so any additional +write() or end() calls have no effect.

+
$stream->end();
+assert($stream->isWritable() === false);
+
+$stream->write('nope'); // NO-OP
+$stream->end(); // NO-OP
+

If this stream is a DuplexStreamInterface, calling this method SHOULD +also end its readable side, unless the stream supports half-open mode. +In other words, after calling this method, these streams SHOULD switch +into non-writable AND non-readable mode, see also isReadable(). +This implies that in this case, the stream SHOULD NOT emit any data +or end events anymore. +Streams MAY choose to use the pause() method logic for this, but +special care may have to be taken to ensure a following call to the +resume() method SHOULD NOT continue emitting readable events.

+

Note that this method should not be confused with the close() method.

+

+close()

+

The close(): void method can be used to +close the stream (forcefully).

+

This method can be used to forcefully close the stream, i.e. close +the stream without waiting for any buffered data to be flushed. +If there's still data in the buffer, this data SHOULD be discarded.

+
$stream->close();
+

Once the stream is closed, it SHOULD emit a close event. +Note that this event SHOULD NOT be emitted more than once, in particular +if this method is called multiple times.

+

After calling this method, the stream MUST switch into a non-writable +mode, see also isWritable(). +This means that no further writes are possible, so any additional +write() or end() calls have no effect.

+
$stream->close();
+assert($stream->isWritable() === false);
+
+$stream->write('nope'); // NO-OP
+$stream->end(); // NO-OP
+

Note that this method should not be confused with the end() method. +Unlike the end() method, this method does not take care of any existing +buffers and simply discards any buffer contents. +Likewise, this method may also be called after calling end() on a +stream in order to stop waiting for the stream to flush its final data.

+
$stream->end();
+$loop->addTimer(1.0, function () use ($stream) {
+    $stream->close();
+});
+

If this stream is a DuplexStreamInterface, you should also notice +how the readable side of the stream also implements a close() method. +In other words, after calling this method, the stream MUST switch into +non-writable AND non-readable mode, see also isReadable().

+

+DuplexStreamInterface

+

The DuplexStreamInterface is responsible for providing an interface for +duplex streams (both readable and writable).

+

It builds on top of the existing interfaces for readable and writable streams +and follows the exact same method and event semantics. +If you're new to this concept, you should look into the +ReadableStreamInterface and WritableStreamInterface first.

+

Besides defining a few methods, this interface also implements the +EventEmitterInterface which allows you to react to the same events defined +on the ReadbleStreamInterface and WritableStreamInterface.

+

The event callback functions MUST be a valid callable that obeys strict +parameter definitions and MUST accept event parameters exactly as documented. +The event callback functions MUST NOT throw an Exception. +The return value of the event callback functions will be ignored and has no +effect, so for performance reasons you're recommended to not return any +excessive data structures.

+

Every implementation of this interface MUST follow these event semantics in +order to be considered a well-behaving stream.

+
+

Note that higher-level implementations of this interface may choose to +define additional events with dedicated semantics not defined as part of +this low-level stream specification. Conformance with these event semantics +is out of scope for this interface, so you may also have to refer to the +documentation of such a higher-level implementation.

+
+

See also ReadableStreamInterface and +WritableStreamInterface for more details.

+

+Creating streams

+

ReactPHP uses the concept of "streams" throughout its ecosystem, so that +many higher-level consumers of this package only deal with +stream usage. +This implies that stream instances are most often created within some +higher-level components and many consumers never actually have to deal with +creating a stream instance.

+
    +
  • Use react/socket +if you want to accept incoming or establish outgoing plaintext TCP/IP or +secure TLS socket connection streams.
  • +
  • Use react/http +if you want to receive an incoming HTTP request body streams.
  • +
  • Use react/child-process +if you want to communicate with child processes via process pipes such as +STDIN, STDOUT, STDERR etc.
  • +
  • Use experimental react/filesystem +if you want to read from / write to the filesystem.
  • +
  • See also the last chapter for more real-world applications.
  • +
+

However, if you are writing a lower-level component or want to create a stream +instance from a stream resource, then the following chapter is for you.

+
+

Note that the following examples use fopen() and stream_socket_client() +for illustration purposes only. +These functions SHOULD NOT be used in a truly async program because each call +may take several seconds to complete and would block the EventLoop otherwise. +Additionally, the fopen() call will return a file handle on some platforms +which may or may not be supported by all EventLoop implementations. +As an alternative, you may want to use higher-level libraries listed above.

+
+

+ReadableResourceStream

+

The ReadableResourceStream is a concrete implementation of the +ReadableStreamInterface for PHP's stream resources.

+

This can be used to represent a read-only resource like a file stream opened in +readable mode or a stream such as STDIN:

+
$stream = new ReadableResourceStream(STDIN, $loop);
+$stream->on('data', function ($chunk) {
+    echo $chunk;
+});
+$stream->on('end', function () {
+    echo 'END';
+});
+

See also ReadableStreamInterface for more details.

+

The first parameter given to the constructor MUST be a valid stream resource +that is opened in reading mode (e.g. fopen() mode r). +Otherwise, it will throw an InvalidArgumentException:

+
// throws InvalidArgumentException
+$stream = new ReadableResourceStream(false, $loop);
+

See also the DuplexResourceStream for read-and-write +stream resources otherwise.

+

Internally, this class tries to enable non-blocking mode on the stream resource +which may not be supported for all stream resources. +Most notably, this is not supported by pipes on Windows (STDIN etc.). +If this fails, it will throw a RuntimeException:

+
// throws RuntimeException on Windows
+$stream = new ReadableResourceStream(STDIN, $loop);
+

Once the constructor is called with a valid stream resource, this class will +take care of the underlying stream resource. +You SHOULD only use its public API and SHOULD NOT interfere with the underlying +stream resource manually.

+

This class takes an optional int|null $readChunkSize parameter that controls +the maximum buffer size in bytes to read at once from the stream. +You can use a null value here in order to apply its default value. +This value SHOULD NOT be changed unless you know what you're doing. +This can be a positive number which means that up to X bytes will be read +at once from the underlying stream resource. Note that the actual number +of bytes read may be lower if the stream resource has less than X bytes +currently available. +This can be -1 which means "read everything available" from the +underlying stream resource. +This should read until the stream resource is not readable anymore +(i.e. underlying buffer drained), note that this does not neccessarily +mean it reached EOF.

+
$stream = new ReadableResourceStream(STDIN, $loop, 8192);
+
+

PHP bug warning: If the PHP process has explicitly been started without a +STDIN stream, then trying to read from STDIN may return data from +another stream resource. This does not happen if you start this with an empty +stream like php test.php < /dev/null instead of php test.php <&-. +See #81 for more details.

+
+

+WritableResourceStream

+

The WritableResourceStream is a concrete implementation of the +WritableStreamInterface for PHP's stream resources.

+

This can be used to represent a write-only resource like a file stream opened in +writable mode or a stream such as STDOUT or STDERR:

+
$stream = new WritableResourceStream(STDOUT, $loop);
+$stream->write('hello!');
+$stream->end();
+

See also WritableStreamInterface for more details.

+

The first parameter given to the constructor MUST be a valid stream resource +that is opened for writing. +Otherwise, it will throw an InvalidArgumentException:

+
// throws InvalidArgumentException
+$stream = new WritableResourceStream(false, $loop);
+

See also the DuplexResourceStream for read-and-write +stream resources otherwise.

+

Internally, this class tries to enable non-blocking mode on the stream resource +which may not be supported for all stream resources. +Most notably, this is not supported by pipes on Windows (STDOUT, STDERR etc.). +If this fails, it will throw a RuntimeException:

+
// throws RuntimeException on Windows
+$stream = new WritableResourceStream(STDOUT, $loop);
+

Once the constructor is called with a valid stream resource, this class will +take care of the underlying stream resource. +You SHOULD only use its public API and SHOULD NOT interfere with the underlying +stream resource manually.

+

Any write() calls to this class will not be performed instantly, but will +be performed asynchronously, once the EventLoop reports the stream resource is +ready to accept data. +For this, it uses an in-memory buffer string to collect all outstanding writes. +This buffer has a soft-limit applied which defines how much data it is willing +to accept before the caller SHOULD stop sending further data.

+

This class takes an optional int|null $writeBufferSoftLimit parameter that controls +this maximum buffer size in bytes. +You can use a null value here in order to apply its default value. +This value SHOULD NOT be changed unless you know what you're doing.

+
$stream = new WritableResourceStream(STDOUT, $loop, 8192);
+

This class takes an optional int|null $writeChunkSize parameter that controls +this maximum buffer size in bytes to write at once to the stream. +You can use a null value here in order to apply its default value. +This value SHOULD NOT be changed unless you know what you're doing. +This can be a positive number which means that up to X bytes will be written +at once to the underlying stream resource. Note that the actual number +of bytes written may be lower if the stream resource has less than X bytes +currently available. +This can be -1 which means "write everything available" to the +underlying stream resource.

+
$stream = new WritableResourceStream(STDOUT, $loop, null, 8192);
+

See also write() for more details.

+

+DuplexResourceStream

+

The DuplexResourceStream is a concrete implementation of the +DuplexStreamInterface for PHP's stream resources.

+

This can be used to represent a read-and-write resource like a file stream opened +in read and write mode mode or a stream such as a TCP/IP connection:

+
$conn = stream_socket_client('tcp://google.com:80');
+$stream = new DuplexResourceStream($conn, $loop);
+$stream->write('hello!');
+$stream->end();
+

See also DuplexStreamInterface for more details.

+

The first parameter given to the constructor MUST be a valid stream resource +that is opened for reading and writing. +Otherwise, it will throw an InvalidArgumentException:

+
// throws InvalidArgumentException
+$stream = new DuplexResourceStream(false, $loop);
+

See also the ReadableResourceStream for read-only +and the WritableResourceStream for write-only +stream resources otherwise.

+

Internally, this class tries to enable non-blocking mode on the stream resource +which may not be supported for all stream resources. +Most notably, this is not supported by pipes on Windows (STDOUT, STDERR etc.). +If this fails, it will throw a RuntimeException:

+
// throws RuntimeException on Windows
+$stream = new DuplexResourceStream(STDOUT, $loop);
+

Once the constructor is called with a valid stream resource, this class will +take care of the underlying stream resource. +You SHOULD only use its public API and SHOULD NOT interfere with the underlying +stream resource manually.

+

This class takes an optional int|null $readChunkSize parameter that controls +the maximum buffer size in bytes to read at once from the stream. +You can use a null value here in order to apply its default value. +This value SHOULD NOT be changed unless you know what you're doing. +This can be a positive number which means that up to X bytes will be read +at once from the underlying stream resource. Note that the actual number +of bytes read may be lower if the stream resource has less than X bytes +currently available. +This can be -1 which means "read everything available" from the +underlying stream resource. +This should read until the stream resource is not readable anymore +(i.e. underlying buffer drained), note that this does not neccessarily +mean it reached EOF.

+
$conn = stream_socket_client('tcp://google.com:80');
+$stream = new DuplexResourceStream($conn, $loop, 8192);
+

Any write() calls to this class will not be performed instantly, but will +be performed asynchronously, once the EventLoop reports the stream resource is +ready to accept data. +For this, it uses an in-memory buffer string to collect all outstanding writes. +This buffer has a soft-limit applied which defines how much data it is willing +to accept before the caller SHOULD stop sending further data.

+

This class takes another optional WritableStreamInterface|null $buffer parameter +that controls this write behavior of this stream. +You can use a null value here in order to apply its default value. +This value SHOULD NOT be changed unless you know what you're doing.

+

If you want to change the write buffer soft limit, you can pass an instance of +WritableResourceStream like this:

+
$conn = stream_socket_client('tcp://google.com:80');
+$buffer = new WritableResourceStream($conn, $loop, 8192);
+$stream = new DuplexResourceStream($conn, $loop, null, $buffer);
+

See also WritableResourceStream for more details.

+

+ThroughStream

+

The ThroughStream implements the +DuplexStreamInterface and will simply pass any data +you write to it through to its readable end.

+
$through = new ThroughStream();
+$through->on('data', $this->expectCallableOnceWith('hello'));
+
+$through->write('hello');
+

Similarly, the end() method will end the stream and emit an +end event and then close() the stream. +The close() method will close the stream and emit a +close event. +Accordingly, this is can also be used in a pipe() context like this:

+
$through = new ThroughStream();
+$source->pipe($through)->pipe($dest);
+

Optionally, its constructor accepts any callable function which will then be +used to filter any data written to it. This function receives a single data +argument as passed to the writable side and must return the data as it will be +passed to its readable end:

+
$through = new ThroughStream('strtoupper');
+$source->pipe($through)->pipe($dest);
+

Note that this class makes no assumptions about any data types. This can be +used to convert data, for example for transforming any structured data into +a newline-delimited JSON (NDJSON) stream like this:

+
$through = new ThroughStream(function ($data) {
+    return json_encode($data) . PHP_EOL;
+});
+$through->on('data', $this->expectCallableOnceWith("[2, true]\n"));
+
+$through->write(array(2, true));
+

The callback function is allowed to throw an Exception. In this case, +the stream will emit an error event and then close() the stream.

+
$through = new ThroughStream(function ($data) {
+    if (!is_string($data)) {
+        throw new \UnexpectedValueException('Only strings allowed');
+    }
+    return $data;
+});
+$through->on('error', $this->expectCallableOnce()));
+$through->on('close', $this->expectCallableOnce()));
+$through->on('data', $this->expectCallableNever()));
+
+$through->write(2);
+

+CompositeStream

+

The CompositeStream implements the +DuplexStreamInterface and can be used to create a +single duplex stream from two individual streams implementing +ReadableStreamInterface and +WritableStreamInterface respectively.

+

This is useful for some APIs which may require a single +DuplexStreamInterface or simply because it's often +more convenient to work with a single stream instance like this:

+
$stdin = new ReadableResourceStream(STDIN, $loop);
+$stdout = new WritableResourceStream(STDOUT, $loop);
+
+$stdio = new CompositeStream($stdin, $stdout);
+
+$stdio->on('data', function ($chunk) use ($stdio) {
+    $stdio->write('You said: ' . $chunk);
+});
+

This is a well-behaving stream which forwards all stream events from the +underlying streams and forwards all streams calls to the underlying streams.

+

If you write() to the duplex stream, it will simply write() to the +writable side and return its status.

+

If you end() the duplex stream, it will end() the writable side and will +pause() the readable side.

+

If you close() the duplex stream, both input streams will be closed. +If either of the two input streams emits a close event, the duplex stream +will also close. +If either of the two input streams is already closed while constructing the +duplex stream, it will close() the other side and return a closed stream.

+

+Usage

+

The following example can be used to pipe the contents of a source file into +a destination file without having to ever read the whole file into memory:

+
$loop = new React\EventLoop\StreamSelectLoop;
+
+$source = new React\Stream\ReadableResourceStream(fopen('source.txt', 'r'), $loop);
+$dest = new React\Stream\WritableResourceStream(fopen('destination.txt', 'w'), $loop);
+
+$source->pipe($dest);
+
+$loop->run();
+
+

Note that this example uses fopen() for illustration purposes only. +This should not be used in a truly async program because the filesystem is +inherently blocking and each call could potentially take several seconds. +See also creating streams for more sophisticated +examples.

+
+

+Install

+

The recommended way to install this library is through Composer. +New to Composer?

+

This will install the latest supported version:

+
$ composer require react/stream:^0.7.7
+

See also the CHANGELOG for details about version upgrades.

+

This project aims to run on any platform and thus does not require any PHP +extensions and supports running on legacy PHP 5.3 through current PHP 7+ and HHVM. +It's highly recommended to use PHP 7+ for this project due to its vast +performance improvements.

+

+Tests

+

To run the test suite, you first need to clone this repo and then install all +dependencies through Composer:

+
$ composer install
+

To run the test suite, go to the project root and run:

+
$ php vendor/bin/phpunit
+

The test suite also contains a number of functional integration tests that rely +on a stable internet connection. +If you do not want to run these, they can simply be skipped like this:

+
$ php vendor/bin/phpunit --exclude-group internet
+

+License

+

MIT, see LICENSE file.

+

+More

+ +
+ +
+
+
+ + + + + + diff --git a/stream/license.html b/stream/license.html new file mode 100644 index 000000000..312c9cf81 --- /dev/null +++ b/stream/license.html @@ -0,0 +1,552 @@ + + + + + + + + Stream: License - ReactPHP + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

Stream License

+ +

Copyright (c) 2012 Igor Wiedler, Chris Boden

+

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions:

+

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.

+
+ +
+
+
+ + + + + +