This commit is contained in:
li
2026-01-28 23:48:20 +08:00
commit b8cd0c9418
1293 changed files with 184011 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
/.idea/
/composer.lock
/composer.phar
/vendor/
+10
View File
@@ -0,0 +1,10 @@
language: php
php:
- 7.3
before_install:
- composer update -n
script:
- ./vendor/bin/phpcs -v --standard=PSR12 bin src
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright Tianfeng.Han [mikan.tenny@gmail.com]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+53
View File
@@ -0,0 +1,53 @@
# Swoole IDE Helper
[![Build Status](https://travis-ci.org/swoole/ide-helper.svg?branch=master)](https://travis-ci.org/swoole/ide-helper)
[![Latest Stable Version](https://poser.pugx.org/swoole/ide-helper/v/stable.svg)](https://packagist.org/packages/swoole/ide-helper)
[![License](https://poser.pugx.org/swoole/ide-helper/license)](LICENSE)
This package contains IDE help files for [Swoole](https://github.com/swoole/swoole-src). You may use it in your IDE to provide accurate autocompletion.
## Install
You may add this package to your project using [Composer](https://getcomposer.org):
```bash
composer require swoole/ide-helper:@dev
# or you may install a specific version, like:
composer require swoole/ide-helper:~4.4.7
```
It's better to install this package on only development systems by adding the `--dev` flag to your Composer commands:
```bash
composer require --dev swoole/ide-helper:@dev
# or you may install a specific version, like:
composer require --dev swoole/ide-helper:~4.4.7
```
## Alternatives
The stubs are created by reverse-engineering the Swoole extensions directly; thus there is no documentation included,
and type hinting is missing in many places. The Swoole team has tried its best to keep the stubs up to date, and we do
want to add inline documentation and type hinting in the future; however, due to limited resources we don't know when it
will be ready.
Here are some alternatives you can consider:
* [eaglewu/swoole-ide-helper](https://github.com/wudi/swoole-ide-helper)
## Generate IDE Help Files
Have Docker running first, then use script _./bin/generator.sh_ to generate IDE help files and put them under folder
`output/` with commands like following:
```bash
./bin/generator.sh 4.4.16
./bin/generator.sh 4.4.16 master
./bin/generator.sh 4.4.16 4.4.16
./bin/generator.sh 4.4.16 b5c9cede8c6150feba50d0e28d56de355fa69d16
./bin/generator.sh 4.5.0RC1 7c913105c3273aab005489d78e0ff9043bfecb54
#
```
The first parameter specifies a stable release of Swoole. The second parameter is optional; it is to specify which
version of [Swoole library](https://github.com/swoole/library) to be integrated with (by default it will have the latest Swoole library included).
+34
View File
@@ -0,0 +1,34 @@
#!/usr/bin/env php
<?php
/**
* To generate IDE help files of Swoole.
*/
declare(strict_types=1);
require_once dirname(__DIR__) . '/vendor/autoload.php';
use Swoole\IDEHelper\AbstractStubGenerator;
use Swoole\IDEHelper\StubGenerators\Swoole;
use Swoole\IDEHelper\StubGenerators\SwooleAsync;
use Swoole\IDEHelper\StubGenerators\SwooleLib;
use Swoole\IDEHelper\StubGenerators\SwooleOrm;
use Swoole\IDEHelper\StubGenerators\SwoolePostgresql;
use Swoole\IDEHelper\StubGenerators\SwooleSerialize;
use Swoole\IDEHelper\StubGenerators\SwooleZookeeper;
/** @var AbstractStubGenerator[] $generators */
$generators = [
new Swoole(),
new SwooleLib(),
// new SwooleAsync(),
// new SwooleOrm(),
// new SwoolePostgresql(),
// new SwooleSerialize(),
// new SwooleZookeeper(),
];
foreach ($generators as $generator) {
$generator->export();
echo "IDE help files for {$generator->getExtension()} {$generator->getVersion()} generated successfully.\n";
}
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
#
# To generate IDE help files of Swoole.
#
# How to use this script:
# ./bin/generator.sh 4.4.16
# ./bin/generator.sh 4.4.16 master
# ./bin/generator.sh 4.4.16 4.4.16
# ./bin/generator.sh 4.4.16 b5c9cede8c6150feba50d0e28d56de355fa69d16
# ./bin/generator.sh 4.5.0RC1 7c913105c3273aab005489d78e0ff9043bfecb54
#
# The first parameter specifies a stable release of Swoole. The second parameter is optional; it is to specify which
# version of Swoole library to be integrated with (by default it will have the latest Swoole library included).
#
set -e
pushd "`dirname "$0"`" > /dev/null
ROOT_PATH="`pwd -P`/.."
popd > /dev/null # Switch back to current directory.
cd "${ROOT_PATH}" # Switch to root directory of project "ide-helper".
rm -rf ./output
docker run --rm \
-v "$(pwd)":/var/www \
-e SWOOLE_LIB_VERSION=${2} \
-t phpswoole/swoole:${1}-php7.1 \
bash -c "composer install && ./bin/generator.php"
git add ./output
+23
View File
@@ -0,0 +1,23 @@
{
"name": "swoole/ide-helper",
"type": "library",
"description": "IDE help files for Swoole.",
"license": "Apache-2.0",
"authors": [
{
"name": "Team Swoole",
"email": "team@swoole.com"
}
],
"require-dev": {
"guzzlehttp/guzzle": "~6.5.0",
"laminas/laminas-code": "~3.4.0",
"squizlabs/php_codesniffer": "~3.5.0",
"symfony/filesystem": "~4.0"
},
"autoload-dev": {
"psr-4": {
"Swoole\\IDEHelper\\": "src/"
}
}
}
@@ -0,0 +1,27 @@
<?php
return array(
//注释
'comment' => '
* 向客户端发送数据
*
* * $data,发送的数据。TCP协议最大不得超过2M,UDP协议不得超过64K
* * 发送成功会返回true,如果连接已被关闭或发送失败会返回false
*
* TCP服务器
* -------------------------------------------------------------------------
* * send操作具有原子性,多个进程同时调用send向同一个连接发送数据,不会发生数据混杂
* * 如果要发送超过2M的数据,可以将数据写入临时文件,然后通过sendfile接口进行发送
*
* swoole-1.6以上版本不需要$from_id
*
* UDP服务器
* ------------------------------------------------------------------------
* * send操作会直接在worker进程内发送数据包,不会再经过主进程转发
* * 使用fd保存客户端IP,from_id保存from_fd和port
* * 如果在onReceive后立即向客户端发送数据,可以不传$reactor_id
* * 如果向其他UDP客户端发送数据,必须要传入$reactor_id
* * 在外网服务中发送超过64K的数据会分成多个传输单元进行发送,如果其中一个单元丢包,会导致整个包被丢弃。所以外网服务,建议发送1.5K以下的数据包
*',
//返回值
'return' => 'bool'
);
+49
View File
@@ -0,0 +1,49 @@
<?php
class_alias(Swoole\Coroutine\Channel::class, Co\Channel::class);
class_alias(Swoole\Coroutine\Client::class, Co\Client::class);
class_alias(Swoole\Coroutine\Context::class, Co\Context::class);
class_alias(Swoole\Coroutine\Http2\Client::class, Co\Http2\Client::class);
class_alias(Swoole\Coroutine\Http2\Client\Exception::class, Co\Http2\Client\Exception::class);
class_alias(Swoole\Coroutine\Http\Client::class, Co\Http\Client::class);
class_alias(Swoole\Coroutine\Http\Client\Exception::class, Co\Http\Client\Exception::class);
class_alias(Swoole\Coroutine\Http\Server::class, Co\Http\Server::class);
class_alias(Swoole\Coroutine\Iterator::class, Co\Iterator::class);
class_alias(Swoole\Coroutine\MySQL::class, Co\MySQL::class);
class_alias(Swoole\Coroutine\MySQL\Exception::class, Co\MySQL\Exception::class);
class_alias(Swoole\Coroutine\MySQL\Statement::class, Co\MySQL\Statement::class);
class_alias(Swoole\Coroutine\Redis::class, Co\Redis::class);
class_alias(Swoole\Coroutine\Scheduler::class, Co\Scheduler::class);
class_alias(Swoole\Coroutine\Socket::class, Co\Socket::class);
class_alias(Swoole\Coroutine\Socket\Exception::class, Co\Socket\Exception::class);
class_alias(Swoole\Coroutine\System::class, Co\System::class);
class_alias(Swoole\Atomic::class, swoole_atomic::class);
class_alias(Swoole\Atomic\Long::class, swoole_atomic_long::class);
class_alias(Swoole\Client::class, swoole_client::class);
class_alias(Swoole\Connection\Iterator::class, swoole_connection_iterator::class);
class_alias(Swoole\Coroutine::class, co::class);
class_alias(Swoole\Coroutine\Channel::class, chan::class);
class_alias(Swoole\Error::class, swoole_error::class);
class_alias(Swoole\Event::class, swoole_event::class);
class_alias(Swoole\Exception::class, swoole_exception::class);
class_alias(Swoole\Http2\Request::class, swoole_http2_request::class);
class_alias(Swoole\Http2\Response::class, swoole_http2_response::class);
class_alias(Swoole\Http\Request::class, swoole_http_request::class);
class_alias(Swoole\Http\Response::class, swoole_http_response::class);
class_alias(Swoole\Http\Server::class, swoole_http_server::class);
class_alias(Swoole\Lock::class, swoole_lock::class);
class_alias(Swoole\Process::class, swoole_process::class);
class_alias(Swoole\Process\Pool::class, swoole_process_pool::class);
class_alias(Swoole\Redis\Server::class, swoole_redis_server::class);
class_alias(Swoole\Runtime::class, swoole_runtime::class);
class_alias(Swoole\Server::class, swoole_server::class);
class_alias(Swoole\Server\Port::class, swoole_server_port::class);
class_alias(Swoole\Server\Task::class, swoole_server_task::class);
class_alias(Swoole\Table::class, swoole_table::class);
class_alias(Swoole\Table\Row::class, swoole_table_row::class);
class_alias(Swoole\Timer::class, swoole_timer::class);
class_alias(Swoole\Timer\Iterator::class, swoole_timer_iterator::class);
class_alias(Swoole\Websocket\Closeframe::class, swoole_websocket_closeframe::class);
class_alias(Swoole\Websocket\Frame::class, swoole_websocket_frame::class);
class_alias(Swoole\Websocket\Server::class, swoole_websocket_server::class);
+387
View File
@@ -0,0 +1,387 @@
<?php
define('SWOOLE_VERSION', '4.5.6');
define('SWOOLE_VERSION_ID', 40506);
define('SWOOLE_MAJOR_VERSION', 4);
define('SWOOLE_MINOR_VERSION', 5);
define('SWOOLE_RELEASE_VERSION', 6);
define('SWOOLE_EXTRA_VERSION', '');
define('SWOOLE_DEBUG', '');
define('SWOOLE_HAVE_COMPRESSION', '1');
define('SWOOLE_HAVE_ZLIB', '1');
define('SWOOLE_USE_HTTP2', '1');
define('SWOOLE_USE_SHORTNAME', '1');
define('SWOOLE_BASE', 1);
define('SWOOLE_PROCESS', 2);
define('SWOOLE_IPC_UNSOCK', 1);
define('SWOOLE_IPC_MSGQUEUE', 2);
define('SWOOLE_IPC_PREEMPTIVE', 3);
define('SWOOLE_SOCK_TCP', 1);
define('SWOOLE_SOCK_TCP6', 3);
define('SWOOLE_SOCK_UDP', 2);
define('SWOOLE_SOCK_UDP6', 4);
define('SWOOLE_SOCK_UNIX_DGRAM', 6);
define('SWOOLE_SOCK_UNIX_STREAM', 5);
define('SWOOLE_TCP', 1);
define('SWOOLE_TCP6', 3);
define('SWOOLE_UDP', 2);
define('SWOOLE_UDP6', 4);
define('SWOOLE_UNIX_DGRAM', 6);
define('SWOOLE_UNIX_STREAM', 5);
define('SWOOLE_SOCK_SYNC', '');
define('SWOOLE_SOCK_ASYNC', '1');
define('SWOOLE_SYNC', 2048);
define('SWOOLE_ASYNC', 1024);
define('SWOOLE_KEEP', 4096);
define('SWOOLE_SSL', 512);
define('SWOOLE_SSLv3_METHOD', 1);
define('SWOOLE_SSLv3_SERVER_METHOD', 2);
define('SWOOLE_SSLv3_CLIENT_METHOD', 3);
define('SWOOLE_TLSv1_METHOD', 6);
define('SWOOLE_TLSv1_SERVER_METHOD', 7);
define('SWOOLE_TLSv1_CLIENT_METHOD', 8);
define('SWOOLE_TLSv1_1_METHOD', 9);
define('SWOOLE_TLSv1_1_SERVER_METHOD', 10);
define('SWOOLE_TLSv1_1_CLIENT_METHOD', 11);
define('SWOOLE_TLSv1_2_METHOD', 12);
define('SWOOLE_TLSv1_2_SERVER_METHOD', 13);
define('SWOOLE_TLSv1_2_CLIENT_METHOD', 14);
define('SWOOLE_DTLS_SERVER_METHOD', 16);
define('SWOOLE_DTLS_CLIENT_METHOD', 15);
define('SWOOLE_SSLv23_METHOD', 0);
define('SWOOLE_SSLv23_SERVER_METHOD', 4);
define('SWOOLE_SSLv23_CLIENT_METHOD', 5);
define('SWOOLE_TLS_METHOD', 0);
define('SWOOLE_TLS_SERVER_METHOD', 4);
define('SWOOLE_TLS_CLIENT_METHOD', 5);
define('SWOOLE_SSL_TLSv1', 8);
define('SWOOLE_SSL_TLSv1_1', 16);
define('SWOOLE_SSL_TLSv1_2', 32);
define('SWOOLE_SSL_TLSv1_3', 64);
define('SWOOLE_SSL_DTLS', 128);
define('SWOOLE_SSL_SSLv2', 2);
define('SWOOLE_EVENT_READ', 512);
define('SWOOLE_EVENT_WRITE', 1024);
define('SWOOLE_STRERROR_SYSTEM', 0);
define('SWOOLE_STRERROR_GAI', 1);
define('SWOOLE_STRERROR_DNS', 2);
define('SWOOLE_STRERROR_SWOOLE', 9);
define('SWOOLE_ERROR_MALLOC_FAIL', 501);
define('SWOOLE_ERROR_SYSTEM_CALL_FAIL', 502);
define('SWOOLE_ERROR_PHP_FATAL_ERROR', 503);
define('SWOOLE_ERROR_NAME_TOO_LONG', 504);
define('SWOOLE_ERROR_INVALID_PARAMS', 505);
define('SWOOLE_ERROR_QUEUE_FULL', 506);
define('SWOOLE_ERROR_OPERATION_NOT_SUPPORT', 507);
define('SWOOLE_ERROR_PROTOCOL_ERROR', 508);
define('SWOOLE_ERROR_WRONG_OPERATION', 509);
define('SWOOLE_ERROR_FILE_NOT_EXIST', 700);
define('SWOOLE_ERROR_FILE_TOO_LARGE', 701);
define('SWOOLE_ERROR_FILE_EMPTY', 702);
define('SWOOLE_ERROR_DNSLOOKUP_DUPLICATE_REQUEST', 703);
define('SWOOLE_ERROR_DNSLOOKUP_RESOLVE_FAILED', 704);
define('SWOOLE_ERROR_DNSLOOKUP_RESOLVE_TIMEOUT', 705);
define('SWOOLE_ERROR_BAD_IPV6_ADDRESS', 706);
define('SWOOLE_ERROR_UNREGISTERED_SIGNAL', 707);
define('SWOOLE_ERROR_EVENT_SOCKET_REMOVED', 800);
define('SWOOLE_ERROR_SESSION_CLOSED_BY_SERVER', 1001);
define('SWOOLE_ERROR_SESSION_CLOSED_BY_CLIENT', 1002);
define('SWOOLE_ERROR_SESSION_CLOSING', 1003);
define('SWOOLE_ERROR_SESSION_CLOSED', 1004);
define('SWOOLE_ERROR_SESSION_NOT_EXIST', 1005);
define('SWOOLE_ERROR_SESSION_INVALID_ID', 1006);
define('SWOOLE_ERROR_SESSION_DISCARD_TIMEOUT_DATA', 1007);
define('SWOOLE_ERROR_SESSION_DISCARD_DATA', 1008);
define('SWOOLE_ERROR_OUTPUT_BUFFER_OVERFLOW', 1009);
define('SWOOLE_ERROR_OUTPUT_SEND_YIELD', 1010);
define('SWOOLE_ERROR_SSL_NOT_READY', 1011);
define('SWOOLE_ERROR_SSL_CANNOT_USE_SENFILE', 1012);
define('SWOOLE_ERROR_SSL_EMPTY_PEER_CERTIFICATE', 1013);
define('SWOOLE_ERROR_SSL_VERIFY_FAILED', 1014);
define('SWOOLE_ERROR_SSL_BAD_CLIENT', 1015);
define('SWOOLE_ERROR_SSL_BAD_PROTOCOL', 1016);
define('SWOOLE_ERROR_SSL_RESET', 1017);
define('SWOOLE_ERROR_SSL_HANDSHAKE_FAILED', 1018);
define('SWOOLE_ERROR_PACKAGE_LENGTH_TOO_LARGE', 1201);
define('SWOOLE_ERROR_PACKAGE_LENGTH_NOT_FOUND', 1202);
define('SWOOLE_ERROR_DATA_LENGTH_TOO_LARGE', 1203);
define('SWOOLE_ERROR_TASK_PACKAGE_TOO_BIG', 2001);
define('SWOOLE_ERROR_TASK_DISPATCH_FAIL', 2002);
define('SWOOLE_ERROR_TASK_TIMEOUT', 2003);
define('SWOOLE_ERROR_HTTP2_STREAM_ID_TOO_BIG', 3001);
define('SWOOLE_ERROR_HTTP2_STREAM_NO_HEADER', 3002);
define('SWOOLE_ERROR_HTTP2_STREAM_NOT_FOUND', 3003);
define('SWOOLE_ERROR_HTTP2_STREAM_IGNORE', 3004);
define('SWOOLE_ERROR_AIO_BAD_REQUEST', 4001);
define('SWOOLE_ERROR_AIO_CANCELED', 4002);
define('SWOOLE_ERROR_AIO_TIMEOUT', 4003);
define('SWOOLE_ERROR_CLIENT_NO_CONNECTION', 5001);
define('SWOOLE_ERROR_SOCKET_CLOSED', 6001);
define('SWOOLE_ERROR_SOCKET_POLL_TIMEOUT', 6002);
define('SWOOLE_ERROR_SOCKS5_UNSUPPORT_VERSION', 7001);
define('SWOOLE_ERROR_SOCKS5_UNSUPPORT_METHOD', 7002);
define('SWOOLE_ERROR_SOCKS5_AUTH_FAILED', 7003);
define('SWOOLE_ERROR_SOCKS5_SERVER_ERROR', 7004);
define('SWOOLE_ERROR_SOCKS5_HANDSHAKE_FAILED', 7005);
define('SWOOLE_ERROR_HTTP_PROXY_HANDSHAKE_ERROR', 7101);
define('SWOOLE_ERROR_HTTP_INVALID_PROTOCOL', 7102);
define('SWOOLE_ERROR_HTTP_PROXY_HANDSHAKE_FAILED', 7103);
define('SWOOLE_ERROR_HTTP_PROXY_BAD_RESPONSE', 7104);
define('SWOOLE_ERROR_WEBSOCKET_BAD_CLIENT', 8501);
define('SWOOLE_ERROR_WEBSOCKET_BAD_OPCODE', 8502);
define('SWOOLE_ERROR_WEBSOCKET_UNCONNECTED', 8503);
define('SWOOLE_ERROR_WEBSOCKET_HANDSHAKE_FAILED', 8504);
define('SWOOLE_ERROR_SERVER_MUST_CREATED_BEFORE_CLIENT', 9001);
define('SWOOLE_ERROR_SERVER_TOO_MANY_SOCKET', 9002);
define('SWOOLE_ERROR_SERVER_WORKER_TERMINATED', 9003);
define('SWOOLE_ERROR_SERVER_INVALID_LISTEN_PORT', 9004);
define('SWOOLE_ERROR_SERVER_TOO_MANY_LISTEN_PORT', 9005);
define('SWOOLE_ERROR_SERVER_PIPE_BUFFER_FULL', 9006);
define('SWOOLE_ERROR_SERVER_NO_IDLE_WORKER', 9007);
define('SWOOLE_ERROR_SERVER_ONLY_START_ONE', 9008);
define('SWOOLE_ERROR_SERVER_SEND_IN_MASTER', 9009);
define('SWOOLE_ERROR_SERVER_INVALID_REQUEST', 9010);
define('SWOOLE_ERROR_SERVER_CONNECT_FAIL', 9011);
define('SWOOLE_ERROR_SERVER_WORKER_EXIT_TIMEOUT', 9012);
define('SWOOLE_ERROR_CO_OUT_OF_COROUTINE', 10001);
define('SWOOLE_ERROR_CO_HAS_BEEN_BOUND', 10002);
define('SWOOLE_ERROR_CO_HAS_BEEN_DISCARDED', 10003);
define('SWOOLE_ERROR_CO_MUTEX_DOUBLE_UNLOCK', 10004);
define('SWOOLE_ERROR_CO_BLOCK_OBJECT_LOCKED', 10005);
define('SWOOLE_ERROR_CO_BLOCK_OBJECT_WAITING', 10006);
define('SWOOLE_ERROR_CO_YIELD_FAILED', 10007);
define('SWOOLE_ERROR_CO_GETCONTEXT_FAILED', 10008);
define('SWOOLE_ERROR_CO_SWAPCONTEXT_FAILED', 10009);
define('SWOOLE_ERROR_CO_MAKECONTEXT_FAILED', 10010);
define('SWOOLE_ERROR_CO_IOCPINIT_FAILED', 10011);
define('SWOOLE_ERROR_CO_PROTECT_STACK_FAILED', 10012);
define('SWOOLE_ERROR_CO_STD_THREAD_LINK_ERROR', 10013);
define('SWOOLE_ERROR_CO_DISABLED_MULTI_THREAD', 10014);
define('SWOOLE_TRACE_SERVER', 2);
define('SWOOLE_TRACE_CLIENT', 4);
define('SWOOLE_TRACE_BUFFER', 8);
define('SWOOLE_TRACE_CONN', 16);
define('SWOOLE_TRACE_EVENT', 32);
define('SWOOLE_TRACE_WORKER', 64);
define('SWOOLE_TRACE_MEMORY', 128);
define('SWOOLE_TRACE_REACTOR', 256);
define('SWOOLE_TRACE_PHP', 512);
define('SWOOLE_TRACE_HTTP', 1024);
define('SWOOLE_TRACE_HTTP2', 2048);
define('SWOOLE_TRACE_EOF_PROTOCOL', 4096);
define('SWOOLE_TRACE_LENGTH_PROTOCOL', 8192);
define('SWOOLE_TRACE_CLOSE', 16384);
define('SWOOLE_TRACE_WEBSOCEKT', 32768);
define('SWOOLE_TRACE_REDIS_CLIENT', 65536);
define('SWOOLE_TRACE_MYSQL_CLIENT', 131072);
define('SWOOLE_TRACE_HTTP_CLIENT', 262144);
define('SWOOLE_TRACE_AIO', 524288);
define('SWOOLE_TRACE_SSL', 1048576);
define('SWOOLE_TRACE_NORMAL', 2097152);
define('SWOOLE_TRACE_CHANNEL', 4194304);
define('SWOOLE_TRACE_TIMER', 8388608);
define('SWOOLE_TRACE_SOCKET', 16777216);
define('SWOOLE_TRACE_COROUTINE', 33554432);
define('SWOOLE_TRACE_CONTEXT', 67108864);
define('SWOOLE_TRACE_CO_HTTP_SERVER', 134217728);
define('SWOOLE_TRACE_TABLE', 268435456);
define('SWOOLE_TRACE_ALL', 4294967295);
define('SWOOLE_LOG_DEBUG', 0);
define('SWOOLE_LOG_TRACE', 1);
define('SWOOLE_LOG_INFO', 2);
define('SWOOLE_LOG_NOTICE', 3);
define('SWOOLE_LOG_WARNING', 4);
define('SWOOLE_LOG_ERROR', 5);
define('SWOOLE_LOG_NONE', 6);
define('SWOOLE_LOG_ROTATION_SINGLE', 0);
define('SWOOLE_LOG_ROTATION_DAILY', 1);
define('SWOOLE_IPC_NONE', 0);
define('SWOOLE_IPC_UNIXSOCK', 1);
define('SWOOLE_IPC_SOCKET', 3);
define('SWOOLE_FILELOCK', 2);
define('SWOOLE_MUTEX', 3);
define('SWOOLE_SEM', 4);
define('SWOOLE_RWLOCK', 1);
define('SWOOLE_SPINLOCK', 5);
define('SIGHUP', 1);
define('SIGINT', 2);
define('SIGQUIT', 3);
define('SIGILL', 4);
define('SIGTRAP', 5);
define('SIGABRT', 6);
define('SIGBUS', 7);
define('SIGFPE', 8);
define('SIGKILL', 9);
define('SIGUSR1', 10);
define('SIGSEGV', 11);
define('SIGUSR2', 12);
define('SIGPIPE', 13);
define('SIGALRM', 14);
define('SIGTERM', 15);
define('SIGSTKFLT', 16);
define('SIGCHLD', 17);
define('SIGCONT', 18);
define('SIGSTOP', 19);
define('SIGTSTP', 20);
define('SIGTTIN', 21);
define('SIGTTOU', 22);
define('SIGURG', 23);
define('SIGXCPU', 24);
define('SIGXFSZ', 25);
define('SIGVTALRM', 26);
define('SIGPROF', 27);
define('SIGWINCH', 28);
define('SIGIO', 29);
define('SIGPWR', 30);
define('SIGSYS', 31);
define('SIG_IGN', 1);
define('SWOOLE_TIMER_MIN_MS', 1);
define('SWOOLE_TIMER_MIN_SEC', 0.001);
define('SWOOLE_TIMER_MAX_MS', 9223372036854775807);
define('SWOOLE_TIMER_MAX_SEC', 9.2233720368548E+15);
define('SWOOLE_DEFAULT_MAX_CORO_NUM', 100000);
define('SWOOLE_CORO_MAX_NUM_LIMIT', 9223372036854775807);
define('SWOOLE_CORO_INIT', 0);
define('SWOOLE_CORO_WAITING', 1);
define('SWOOLE_CORO_RUNNING', 2);
define('SWOOLE_CORO_END', 3);
define('SWOOLE_EXIT_IN_COROUTINE', 2);
define('SWOOLE_EXIT_IN_SERVER', 4);
define('SWOOLE_CHANNEL_OK', 0);
define('SWOOLE_CHANNEL_TIMEOUT', -1);
define('SWOOLE_CHANNEL_CLOSED', -2);
define('SWOOLE_HOOK_TCP', 2);
define('SWOOLE_HOOK_UDP', 4);
define('SWOOLE_HOOK_UNIX', 8);
define('SWOOLE_HOOK_UDG', 16);
define('SWOOLE_HOOK_SSL', 32);
define('SWOOLE_HOOK_TLS', 64);
define('SWOOLE_HOOK_STREAM_FUNCTION', 128);
define('SWOOLE_HOOK_STREAM_SELECT', 128);
define('SWOOLE_HOOK_FILE', 256);
define('SWOOLE_HOOK_SLEEP', 512);
define('SWOOLE_HOOK_PROC', 1024);
define('SWOOLE_HOOK_CURL', 268435456);
define('SWOOLE_HOOK_BLOCKING_FUNCTION', 1073741824);
define('SWOOLE_HOOK_ALL', 2147483647);
define('SOCKET_ECANCELED', 125);
define('SWOOLE_HTTP_CLIENT_ESTATUS_CONNECT_FAILED', -1);
define('SWOOLE_HTTP_CLIENT_ESTATUS_REQUEST_TIMEOUT', -2);
define('SWOOLE_HTTP_CLIENT_ESTATUS_SERVER_RESET', -3);
define('SWOOLE_MYSQLND_CR_UNKNOWN_ERROR', 2000);
define('SWOOLE_MYSQLND_CR_CONNECTION_ERROR', 2002);
define('SWOOLE_MYSQLND_CR_SERVER_GONE_ERROR', 2006);
define('SWOOLE_MYSQLND_CR_OUT_OF_MEMORY', 2008);
define('SWOOLE_MYSQLND_CR_SERVER_LOST', 2013);
define('SWOOLE_MYSQLND_CR_COMMANDS_OUT_OF_SYNC', 2014);
define('SWOOLE_MYSQLND_CR_CANT_FIND_CHARSET', 2019);
define('SWOOLE_MYSQLND_CR_MALFORMED_PACKET', 2027);
define('SWOOLE_MYSQLND_CR_NOT_IMPLEMENTED', 2054);
define('SWOOLE_MYSQLND_CR_NO_PREPARE_STMT', 2030);
define('SWOOLE_MYSQLND_CR_PARAMS_NOT_BOUND', 2031);
define('SWOOLE_MYSQLND_CR_INVALID_PARAMETER_NO', 2034);
define('SWOOLE_MYSQLND_CR_INVALID_BUFFER_USE', 2035);
define('SWOOLE_REDIS_MODE_MULTI', 0);
define('SWOOLE_REDIS_MODE_PIPELINE', 1);
define('SWOOLE_REDIS_TYPE_NOT_FOUND', 0);
define('SWOOLE_REDIS_TYPE_STRING', 1);
define('SWOOLE_REDIS_TYPE_SET', 2);
define('SWOOLE_REDIS_TYPE_LIST', 3);
define('SWOOLE_REDIS_TYPE_ZSET', 4);
define('SWOOLE_REDIS_TYPE_HASH', 5);
define('SWOOLE_REDIS_ERR_IO', 1);
define('SWOOLE_REDIS_ERR_OTHER', 2);
define('SWOOLE_REDIS_ERR_EOF', 3);
define('SWOOLE_REDIS_ERR_PROTOCOL', 4);
define('SWOOLE_REDIS_ERR_OOM', 5);
define('SWOOLE_REDIS_ERR_CLOSED', 6);
define('SWOOLE_REDIS_ERR_NOAUTH', 7);
define('SWOOLE_REDIS_ERR_ALLOC', 8);
define('SWOOLE_HTTP2_TYPE_DATA', 0);
define('SWOOLE_HTTP2_TYPE_HEADERS', 1);
define('SWOOLE_HTTP2_TYPE_PRIORITY', 2);
define('SWOOLE_HTTP2_TYPE_RST_STREAM', 3);
define('SWOOLE_HTTP2_TYPE_SETTINGS', 4);
define('SWOOLE_HTTP2_TYPE_PUSH_PROMISE', 5);
define('SWOOLE_HTTP2_TYPE_PING', 6);
define('SWOOLE_HTTP2_TYPE_GOAWAY', 7);
define('SWOOLE_HTTP2_TYPE_WINDOW_UPDATE', 8);
define('SWOOLE_HTTP2_TYPE_CONTINUATION', 9);
define('SWOOLE_HTTP2_ERROR_NO_ERROR', 0);
define('SWOOLE_HTTP2_ERROR_PROTOCOL_ERROR', 1);
define('SWOOLE_HTTP2_ERROR_INTERNAL_ERROR', 2);
define('SWOOLE_HTTP2_ERROR_FLOW_CONTROL_ERROR', 3);
define('SWOOLE_HTTP2_ERROR_SETTINGS_TIMEOUT', 4);
define('SWOOLE_HTTP2_ERROR_STREAM_CLOSED', 5);
define('SWOOLE_HTTP2_ERROR_FRAME_SIZE_ERROR', 6);
define('SWOOLE_HTTP2_ERROR_REFUSED_STREAM', 7);
define('SWOOLE_HTTP2_ERROR_CANCEL', 8);
define('SWOOLE_HTTP2_ERROR_COMPRESSION_ERROR', 9);
define('SWOOLE_HTTP2_ERROR_CONNECT_ERROR', 10);
define('SWOOLE_HTTP2_ERROR_ENHANCE_YOUR_CALM', 11);
define('SWOOLE_HTTP2_ERROR_INADEQUATE_SECURITY', 12);
define('SWOOLE_DISPATCH_RESULT_DISCARD_PACKET', -1);
define('SWOOLE_DISPATCH_RESULT_CLOSE_CONNECTION', -2);
define('SWOOLE_DISPATCH_RESULT_USERFUNC_FALLBACK', -3);
define('SWOOLE_TASK_TMPFILE', 1);
define('SWOOLE_TASK_SERIALIZE', 2);
define('SWOOLE_TASK_NONBLOCK', 4);
define('SWOOLE_TASK_CALLBACK', 8);
define('SWOOLE_TASK_WAITALL', 16);
define('SWOOLE_TASK_COROUTINE', 32);
define('SWOOLE_TASK_PEEK', 64);
define('SWOOLE_TASK_NOREPLY', 128);
define('SWOOLE_WORKER_BUSY', 1);
define('SWOOLE_WORKER_IDLE', 2);
define('SWOOLE_WORKER_EXIT', 3);
define('SWOOLE_WEBSOCKET_STATUS_CONNECTION', 1);
define('SWOOLE_WEBSOCKET_STATUS_HANDSHAKE', 2);
define('SWOOLE_WEBSOCKET_STATUS_ACTIVE', 3);
define('SWOOLE_WEBSOCKET_STATUS_CLOSING', 4);
define('SWOOLE_WEBSOCKET_OPCODE_CONTINUATION', 0);
define('SWOOLE_WEBSOCKET_OPCODE_TEXT', 1);
define('SWOOLE_WEBSOCKET_OPCODE_BINARY', 2);
define('SWOOLE_WEBSOCKET_OPCODE_CLOSE', 8);
define('SWOOLE_WEBSOCKET_OPCODE_PING', 9);
define('SWOOLE_WEBSOCKET_OPCODE_PONG', 10);
define('SWOOLE_WEBSOCKET_FLAG_FIN', 1);
define('SWOOLE_WEBSOCKET_FLAG_RSV1', 4);
define('SWOOLE_WEBSOCKET_FLAG_RSV2', 8);
define('SWOOLE_WEBSOCKET_FLAG_RSV3', 16);
define('SWOOLE_WEBSOCKET_FLAG_MASK', 32);
define('SWOOLE_WEBSOCKET_FLAG_COMPRESS', 2);
define('SWOOLE_WEBSOCKET_CLOSE_NORMAL', 1000);
define('SWOOLE_WEBSOCKET_CLOSE_GOING_AWAY', 1001);
define('SWOOLE_WEBSOCKET_CLOSE_PROTOCOL_ERROR', 1002);
define('SWOOLE_WEBSOCKET_CLOSE_DATA_ERROR', 1003);
define('SWOOLE_WEBSOCKET_CLOSE_STATUS_ERROR', 1005);
define('SWOOLE_WEBSOCKET_CLOSE_ABNORMAL', 1006);
define('SWOOLE_WEBSOCKET_CLOSE_MESSAGE_ERROR', 1007);
define('SWOOLE_WEBSOCKET_CLOSE_POLICY_ERROR', 1008);
define('SWOOLE_WEBSOCKET_CLOSE_MESSAGE_TOO_BIG', 1009);
define('SWOOLE_WEBSOCKET_CLOSE_EXTENSION_MISSING', 1010);
define('SWOOLE_WEBSOCKET_CLOSE_SERVER_ERROR', 1011);
define('SWOOLE_WEBSOCKET_CLOSE_TLS', 1015);
define('WEBSOCKET_STATUS_CONNECTION', 1);
define('WEBSOCKET_STATUS_HANDSHAKE', 2);
define('WEBSOCKET_STATUS_FRAME', 3);
define('WEBSOCKET_STATUS_ACTIVE', 3);
define('WEBSOCKET_STATUS_CLOSING', 4);
define('WEBSOCKET_OPCODE_CONTINUATION', 0);
define('WEBSOCKET_OPCODE_TEXT', 1);
define('WEBSOCKET_OPCODE_BINARY', 2);
define('WEBSOCKET_OPCODE_CLOSE', 8);
define('WEBSOCKET_OPCODE_PING', 9);
define('WEBSOCKET_OPCODE_PONG', 10);
define('WEBSOCKET_CLOSE_NORMAL', 1000);
define('WEBSOCKET_CLOSE_GOING_AWAY', 1001);
define('WEBSOCKET_CLOSE_PROTOCOL_ERROR', 1002);
define('WEBSOCKET_CLOSE_DATA_ERROR', 1003);
define('WEBSOCKET_CLOSE_STATUS_ERROR', 1005);
define('WEBSOCKET_CLOSE_ABNORMAL', 1006);
define('WEBSOCKET_CLOSE_MESSAGE_ERROR', 1007);
define('WEBSOCKET_CLOSE_POLICY_ERROR', 1008);
define('WEBSOCKET_CLOSE_MESSAGE_TOO_BIG', 1009);
define('WEBSOCKET_CLOSE_EXTENSION_MISSING', 1010);
define('WEBSOCKET_CLOSE_SERVER_ERROR', 1011);
define('WEBSOCKET_CLOSE_TLS', 1015);
+300
View File
@@ -0,0 +1,300 @@
<?php
/**
* @return mixed
*/
function swoole_version(){}
/**
* @return mixed
*/
function swoole_cpu_num(){}
/**
* @return mixed
*/
function swoole_last_error(){}
/**
* @param $domain_name[required]
* @param $timeout[optional]
* @return mixed
*/
function swoole_async_dns_lookup_coro($domain_name, $timeout = null){}
/**
* @param $settings[required]
* @return mixed
*/
function swoole_async_set($settings){}
/**
* @param $func[required]
* @param $params[optional]
* @return mixed
*/
function swoole_coroutine_create($func, $params = null){}
/**
* @param $callback[required]
* @return mixed
*/
function swoole_coroutine_defer($callback){}
/**
* @param $read_array[required]
* @param $write_array[required]
* @param $error_array[required]
* @param $timeout[optional]
* @return mixed
*/
function swoole_client_select(&$read_array, &$write_array, &$error_array, $timeout = null){}
/**
* @param $read_array[required]
* @param $write_array[required]
* @param $error_array[required]
* @param $timeout[optional]
* @return mixed
*/
function swoole_select(&$read_array, &$write_array, &$error_array, $timeout = null){}
/**
* @param $process_name[required]
* @return mixed
*/
function swoole_set_process_name($process_name){}
/**
* @return mixed
*/
function swoole_get_local_ip(){}
/**
* @return mixed
*/
function swoole_get_local_mac(){}
/**
* @param $errno[required]
* @param $error_type[optional]
* @return mixed
*/
function swoole_strerror($errno, $error_type = null){}
/**
* @return mixed
*/
function swoole_errno(){}
/**
* @param $data[required]
* @param $type[optional]
* @return mixed
*/
function swoole_hashcode($data, $type = null){}
/**
* @param $suffix[required]
* @param $mime_type[required]
* @return mixed
*/
function swoole_mime_type_add($suffix, $mime_type){}
/**
* @param $suffix[required]
* @param $mime_type[required]
* @return mixed
*/
function swoole_mime_type_set($suffix, $mime_type){}
/**
* @param $suffix[required]
* @return mixed
*/
function swoole_mime_type_delete($suffix){}
/**
* @param $filename[required]
* @return mixed
*/
function swoole_mime_type_get($filename){}
/**
* @param $filename[required]
* @return mixed
*/
function swoole_get_mime_type($filename){}
/**
* @param $filename[required]
* @return mixed
*/
function swoole_mime_type_exists($filename){}
/**
* @return mixed
*/
function swoole_mime_type_list(){}
/**
* @return mixed
*/
function swoole_clear_dns_cache(){}
/**
* @param $str[required]
* @param $offset[required]
* @param $length[optional]
* @param $options[optional]
* @return mixed
*/
function swoole_substr_unserialize($str, $offset, $length = null, $options = null){}
/**
* @param $json[required]
* @param $offset[required]
* @param $length[optional]
* @param $associative[optional]
* @param $depth[optional]
* @param $flags[optional]
* @return mixed
*/
function swoole_substr_json_decode($json, $offset, $length = null, $associative = null, $depth = null, $flags = null){}
/**
* @return mixed
*/
function swoole_internal_call_user_shutdown_begin(){}
/**
* @param $func[required]
* @return mixed
*/
function go($func){}
/**
* @param $callback[required]
* @return mixed
*/
function defer($callback){}
/**
* @param $fd[required]
* @param $read_callback[required]
* @param $write_callback[optional]
* @param $events[optional]
* @return mixed
*/
function swoole_event_add($fd, $read_callback, $write_callback = null, $events = null){}
/**
* @param $fd[required]
* @return mixed
*/
function swoole_event_del($fd){}
/**
* @param $fd[required]
* @param $read_callback[optional]
* @param $write_callback[optional]
* @param $events[optional]
* @return mixed
*/
function swoole_event_set($fd, $read_callback = null, $write_callback = null, $events = null){}
/**
* @param $fd[required]
* @param $events[optional]
* @return mixed
*/
function swoole_event_isset($fd, $events = null){}
/**
* @return mixed
*/
function swoole_event_dispatch(){}
/**
* @param $callback[required]
* @return mixed
*/
function swoole_event_defer($callback){}
/**
* @param $callback[required]
* @param $before[optional]
* @return mixed
*/
function swoole_event_cycle($callback, $before = null){}
/**
* @param $fd[required]
* @param $data[required]
* @return mixed
*/
function swoole_event_write($fd, $data){}
/**
* @return mixed
*/
function swoole_event_wait(){}
/**
* @return mixed
*/
function swoole_event_exit(){}
/**
* @param $settings[required]
* @return mixed
*/
function swoole_timer_set($settings){}
/**
* @param $ms[required]
* @param $callback[required]
* @return mixed
*/
function swoole_timer_after($ms, $callback){}
/**
* @param $ms[required]
* @param $callback[required]
* @return mixed
*/
function swoole_timer_tick($ms, $callback){}
/**
* @param $timer_id[required]
* @return mixed
*/
function swoole_timer_exists($timer_id){}
/**
* @param $timer_id[required]
* @return mixed
*/
function swoole_timer_info($timer_id){}
/**
* @return mixed
*/
function swoole_timer_stats(){}
/**
* @return mixed
*/
function swoole_timer_list(){}
/**
* @param $timer_id[required]
* @return mixed
*/
function swoole_timer_clear($timer_id){}
/**
* @return mixed
*/
function swoole_timer_clear_all(){}
@@ -0,0 +1,62 @@
<?php
namespace Swoole;
class Atomic
{
public function __construct($value = null)
{
}
/**
* @return mixed
*/
public function add($add_value = null)
{
}
/**
* @return mixed
*/
public function sub($sub_value = null)
{
}
/**
* @return mixed
*/
public function get()
{
}
/**
* @return mixed
*/
public function set($value)
{
}
/**
* @return mixed
*/
public function wait($timeout = null)
{
}
/**
* @return mixed
*/
public function wakeup($count = null)
{
}
/**
* @return mixed
*/
public function cmpset($cmp_value, $new_value)
{
}
}
@@ -0,0 +1,48 @@
<?php
namespace Swoole\Atomic;
class Long
{
public function __construct($value = null)
{
}
/**
* @return mixed
*/
public function add($add_value = null)
{
}
/**
* @return mixed
*/
public function sub($sub_value = null)
{
}
/**
* @return mixed
*/
public function get()
{
}
/**
* @return mixed
*/
public function set($value)
{
}
/**
* @return mixed
*/
public function cmpset($cmp_value, $new_value)
{
}
}
@@ -0,0 +1,150 @@
<?php
namespace Swoole;
class Client
{
public const MSG_OOB = 1;
public const MSG_PEEK = 2;
public const MSG_DONTWAIT = 64;
public const MSG_WAITALL = 256;
public const SHUT_RDWR = 2;
public const SHUT_RD = 0;
public const SHUT_WR = 1;
public $errCode = 0;
public $sock = -1;
public $reuse = false;
public $reuseCount = 0;
public $type = 0;
public $id;
public $setting;
public function __construct($type, $async = null, $id = null)
{
}
public function __destruct()
{
}
/**
* @return mixed
*/
public function set(array $settings)
{
}
/**
* @return mixed
*/
public function connect($host, $port = null, $timeout = null, $sock_flag = null)
{
}
/**
* @return mixed
*/
public function recv($size = null, $flag = null)
{
}
/**
* @return mixed
*/
public function send($data, $flag = null)
{
}
/**
* @return mixed
*/
public function sendfile($filename, $offset = null, $length = null)
{
}
/**
* @return mixed
*/
public function sendto($ip, $port, $data)
{
}
/**
* @return mixed
*/
public function shutdown($how)
{
}
/**
* @return mixed
*/
public function enableSSL()
{
}
/**
* @return mixed
*/
public function getPeerCert()
{
}
/**
* @return mixed
*/
public function verifyPeerCert()
{
}
/**
* @return mixed
*/
public function isConnected()
{
}
/**
* @return mixed
*/
public function getsockname()
{
}
/**
* @return mixed
*/
public function getpeername()
{
}
/**
* @return mixed
*/
public function close($force = null)
{
}
/**
* @return mixed
*/
public function getSocket()
{
}
}
@@ -0,0 +1,87 @@
<?php
namespace Swoole\Connection;
class Iterator implements \Iterator, \ArrayAccess
{
public function __construct()
{
}
public function __destruct()
{
}
/**
* @return mixed
*/
public function rewind()
{
}
/**
* @return mixed
*/
public function next()
{
}
/**
* @return mixed
*/
public function current()
{
}
/**
* @return mixed
*/
public function key()
{
}
/**
* @return mixed
*/
public function valid()
{
}
/**
* @return mixed
*/
public function count()
{
}
/**
* @return mixed
*/
public function offsetExists($fd)
{
}
/**
* @return mixed
*/
public function offsetGet($fd)
{
}
/**
* @return mixed
*/
public function offsetSet($fd, $value)
{
}
/**
* @return mixed
*/
public function offsetUnset($fd)
{
}
}
@@ -0,0 +1,240 @@
<?php
namespace Swoole;
class Coroutine
{
/**
* @return mixed
*/
public static function create(callable $func, ... $params)
{
}
/**
* @return mixed
*/
public static function defer($callback)
{
}
/**
* @return mixed
*/
public static function set($options)
{
}
/**
* @return mixed
*/
public static function exists($cid)
{
}
/**
* @return mixed
*/
public static function yield()
{
}
/**
* @return mixed
*/
public static function suspend()
{
}
/**
* @return mixed
*/
public static function resume($cid)
{
}
/**
* @return mixed
*/
public static function stats()
{
}
/**
* @return mixed
*/
public static function getCid()
{
}
/**
* @return mixed
*/
public static function getuid()
{
}
/**
* @return mixed
*/
public static function getPcid($cid = null)
{
}
/**
* @return mixed
*/
public static function getContext($cid = null)
{
}
/**
* @return mixed
*/
public static function getBackTrace($cid = null, $options = null, $limit = null)
{
}
/**
* @return mixed
*/
public static function getElapsed($cid = null)
{
}
/**
* @return mixed
*/
public static function list()
{
}
/**
* @return mixed
*/
public static function listCoroutines()
{
}
/**
* @return mixed
*/
public static function enableScheduler()
{
}
/**
* @return mixed
*/
public static function disableScheduler()
{
}
/**
* @return mixed
*/
public static function gethostbyname($domain_name, $family = null, $timeout = null)
{
}
/**
* @return mixed
*/
public static function dnsLookup($domain_name, $timeout = null)
{
}
/**
* @return mixed
*/
public static function exec($command, $get_error_stream = null)
{
}
/**
* @return mixed
*/
public static function sleep($seconds)
{
}
/**
* @return mixed
*/
public static function getaddrinfo($hostname, $family = null, $socktype = null, $protocol = null, $service = null, $timeout = null)
{
}
/**
* @return mixed
*/
public static function statvfs($path)
{
}
/**
* @return mixed
*/
public static function readFile($filename)
{
}
/**
* @return mixed
*/
public static function writeFile($filename, $data, $flags = null)
{
}
/**
* @return mixed
*/
public static function wait($timeout = null)
{
}
/**
* @return mixed
*/
public static function waitPid($pid, $timeout = null)
{
}
/**
* @return mixed
*/
public static function waitSignal($signo, $timeout = null)
{
}
/**
* @return mixed
*/
public static function waitEvent($fd, $events = null, $timeout = null)
{
}
/**
* @return mixed
*/
public static function fread($handle, $length = null)
{
}
/**
* @return mixed
*/
public static function fgets($handle)
{
}
/**
* @return mixed
*/
public static function fwrite($handle, $string, $length = null)
{
}
}
@@ -0,0 +1,66 @@
<?php
namespace Swoole\Coroutine;
class Channel
{
public $capacity = 0;
public $errCode = 0;
public function __construct($size = null)
{
}
/**
* @return mixed
*/
public function push($data, $timeout = null)
{
}
/**
* @return mixed
*/
public function pop($timeout = null)
{
}
/**
* @return mixed
*/
public function isEmpty()
{
}
/**
* @return mixed
*/
public function isFull()
{
}
/**
* @return mixed
*/
public function close()
{
}
/**
* @return mixed
*/
public function stats()
{
}
/**
* @return mixed
*/
public function length()
{
}
}
@@ -0,0 +1,151 @@
<?php
namespace Swoole\Coroutine;
class Client
{
public const MSG_OOB = 1;
public const MSG_PEEK = 2;
public const MSG_DONTWAIT = 64;
public const MSG_WAITALL = 256;
public $errCode = 0;
public $errMsg = '';
public $fd = -1;
private $socket;
public $type = 1;
public $setting;
public $connected = false;
public function __construct($type)
{
}
public function __destruct()
{
}
/**
* @return mixed
*/
public function set(array $settings)
{
}
/**
* @return mixed
*/
public function connect($host, $port = null, $timeout = null, $sock_flag = null)
{
}
/**
* @return mixed
*/
public function recv($timeout = null)
{
}
/**
* @return mixed
*/
public function peek($length = null)
{
}
/**
* @return mixed
*/
public function send($data)
{
}
/**
* @return mixed
*/
public function sendfile($filename, $offset = null, $length = null)
{
}
/**
* @return mixed
*/
public function sendto($address, $port, $data)
{
}
/**
* @return mixed
*/
public function recvfrom($length, &$address, &$port = null)
{
}
/**
* @return mixed
*/
public function enableSSL()
{
}
/**
* @return mixed
*/
public function getPeerCert()
{
}
/**
* @return mixed
*/
public function verifyPeerCert()
{
}
/**
* @return mixed
*/
public function isConnected()
{
}
/**
* @return mixed
*/
public function getsockname()
{
}
/**
* @return mixed
*/
public function getpeername()
{
}
/**
* @return mixed
*/
public function close()
{
}
/**
* @return mixed
*/
public function exportSocket()
{
}
}
@@ -0,0 +1,13 @@
<?php
namespace Swoole\Coroutine;
class Context extends \ArrayObject
{
public const STD_PROP_LIST = 1;
public const ARRAY_AS_PROPS = 2;
}
@@ -0,0 +1,235 @@
<?php
namespace Swoole\Coroutine\Http;
class Client
{
public $errCode = 0;
public $errMsg = '';
public $connected = false;
public $host = '';
public $port = 0;
public $ssl = false;
public $setting;
public $requestMethod;
public $requestHeaders;
public $requestBody;
public $uploadFiles;
public $downloadFile;
public $downloadOffset = 0;
public $statusCode = 0;
public $headers;
public $set_cookie_headers;
public $cookies;
public $body = '';
public function __construct($host, $port = null, $ssl = null)
{
}
public function __destruct()
{
}
/**
* @return mixed
*/
public function set(array $settings)
{
}
/**
* @return mixed
*/
public function getDefer()
{
}
/**
* @return mixed
*/
public function setDefer($defer = null)
{
}
/**
* @return mixed
*/
public function setMethod($method)
{
}
/**
* @return mixed
*/
public function setHeaders(array $headers)
{
}
/**
* @return mixed
*/
public function setBasicAuth($username, $password)
{
}
/**
* @return mixed
*/
public function setCookies(array $cookies)
{
}
/**
* @return mixed
*/
public function setData($data)
{
}
/**
* @return mixed
*/
public function addFile($path, $name, $type = null, $filename = null, $offset = null, $length = null)
{
}
/**
* @return mixed
*/
public function addData($path, $name, $type = null, $filename = null)
{
}
/**
* @return mixed
*/
public function execute($path)
{
}
/**
* @return mixed
*/
public function getpeername()
{
}
/**
* @return mixed
*/
public function getsockname()
{
}
/**
* @return mixed
*/
public function get($path)
{
}
/**
* @return mixed
*/
public function post($path, $data)
{
}
/**
* @return mixed
*/
public function download($path, $file, $offset = null)
{
}
/**
* @return mixed
*/
public function getBody()
{
}
/**
* @return mixed
*/
public function getHeaders()
{
}
/**
* @return mixed
*/
public function getCookies()
{
}
/**
* @return mixed
*/
public function getStatusCode()
{
}
/**
* @return mixed
*/
public function getHeaderOut()
{
}
/**
* @return mixed
*/
public function getPeerCert()
{
}
/**
* @return mixed
*/
public function upgrade($path)
{
}
/**
* @return mixed
*/
public function push($data, $opcode = null, $flags = null)
{
}
/**
* @return mixed
*/
public function recv($timeout = null)
{
}
/**
* @return mixed
*/
public function close()
{
}
}
@@ -0,0 +1,9 @@
<?php
namespace Swoole\Coroutine\Http\Client;
class Exception extends \Swoole\Exception
{
}
@@ -0,0 +1,66 @@
<?php
namespace Swoole\Coroutine\Http;
class Server
{
public $fd = -1;
public $host;
public $port = -1;
public $ssl = false;
public $settings;
public $errCode = 0;
public $errMsg = '';
public function __construct($host, $port = null, $ssl = null, $reuse_port = null)
{
}
public function __destruct()
{
}
/**
* @return mixed
*/
public function set(array $settings)
{
}
/**
* @return mixed
*/
public function handle($pattern, callable $callback)
{
}
/**
* @return mixed
*/
private function onAccept()
{
}
/**
* @return mixed
*/
public function start()
{
}
/**
* @return mixed
*/
public function shutdown()
{
}
}
@@ -0,0 +1,112 @@
<?php
namespace Swoole\Coroutine\Http2;
class Client
{
public $errCode = 0;
public $errMsg = 0;
public $sock = -1;
public $type = 0;
public $setting;
public $connected = false;
public $host;
public $port = 0;
public $ssl = false;
public function __construct($host, $port = null, $ssl = null)
{
}
public function __destruct()
{
}
/**
* @return mixed
*/
public function set(array $settings)
{
}
/**
* @return mixed
*/
public function connect()
{
}
/**
* @return mixed
*/
public function stats($key = null)
{
}
/**
* @return mixed
*/
public function isStreamExist($stream_id)
{
}
/**
* @return mixed
*/
public function send($request)
{
}
/**
* @return mixed
*/
public function write($stream_id, $data, $end_stream = null)
{
}
/**
* @return mixed
*/
public function recv($timeout = null)
{
}
/**
* @return mixed
*/
public function read($timeout = null)
{
}
/**
* @return mixed
*/
public function goaway($error_code = null, $debug_data = null)
{
}
/**
* @return mixed
*/
public function ping()
{
}
/**
* @return mixed
*/
public function close()
{
}
}
@@ -0,0 +1,9 @@
<?php
namespace Swoole\Coroutine\Http2\Client;
class Exception extends \Swoole\Exception
{
}
@@ -0,0 +1,13 @@
<?php
namespace Swoole\Coroutine;
class Iterator extends \ArrayIterator
{
public const STD_PROP_LIST = 1;
public const ARRAY_AS_PROPS = 2;
}
@@ -0,0 +1,133 @@
<?php
namespace Swoole\Coroutine;
class MySQL
{
public $serverInfo;
public $sock = -1;
public $connected = false;
public $connect_errno = 0;
public $connect_error = '';
public $affected_rows = 0;
public $insert_id = 0;
public $error = '';
public $errno = 0;
public function __construct()
{
}
public function __destruct()
{
}
/**
* @return mixed
*/
public function getDefer()
{
}
/**
* @return mixed
*/
public function setDefer($defer = null)
{
}
/**
* @return mixed
*/
public function connect(array $server_config = null)
{
}
/**
* @return mixed
*/
public function query($sql, $timeout = null)
{
}
/**
* @return mixed
*/
public function fetch()
{
}
/**
* @return mixed
*/
public function fetchAll()
{
}
/**
* @return mixed
*/
public function nextResult()
{
}
/**
* @return mixed
*/
public function prepare($query, $timeout = null)
{
}
/**
* @return mixed
*/
public function recv()
{
}
/**
* @return mixed
*/
public function begin($timeout = null)
{
}
/**
* @return mixed
*/
public function commit($timeout = null)
{
}
/**
* @return mixed
*/
public function rollback($timeout = null)
{
}
/**
* @return mixed
*/
public function escape($string, $flags = null)
{
}
/**
* @return mixed
*/
public function close()
{
}
}
@@ -0,0 +1,9 @@
<?php
namespace Swoole\Coroutine\MySQL;
class Exception extends \Swoole\Exception
{
}
@@ -0,0 +1,61 @@
<?php
namespace Swoole\Coroutine\MySQL;
class Statement
{
public $id = 0;
public $affected_rows = 0;
public $insert_id = 0;
public $error = '';
public $errno = 0;
/**
* @return mixed
*/
public function execute($params = null, $timeout = null)
{
}
/**
* @return mixed
*/
public function fetch($timeout = null)
{
}
/**
* @return mixed
*/
public function fetchAll($timeout = null)
{
}
/**
* @return mixed
*/
public function nextResult($timeout = null)
{
}
/**
* @return mixed
*/
public function recv($timeout = null)
{
}
/**
* @return mixed
*/
public function close()
{
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,37 @@
<?php
namespace Swoole\Coroutine;
class Scheduler
{
/**
* @return mixed
*/
public function add(callable $func, ... $params)
{
}
/**
* @return mixed
*/
public function parallel($n, callable $func = null, ... $params)
{
}
/**
* @return mixed
*/
public function set(array $settings)
{
}
/**
* @return mixed
*/
public function start()
{
}
}
@@ -0,0 +1,180 @@
<?php
namespace Swoole\Coroutine;
class Socket
{
public $fd = -1;
public $errCode = 0;
public $errMsg = '';
public function __construct($domain, $type, $protocol = null)
{
}
/**
* @return mixed
*/
public function bind($address, $port = null)
{
}
/**
* @return mixed
*/
public function listen($backlog = null)
{
}
/**
* @return mixed
*/
public function accept($timeout = null)
{
}
/**
* @return mixed
*/
public function connect($host, $port = null, $timeout = null)
{
}
/**
* @return mixed
*/
public function checkLiveness()
{
}
/**
* @return mixed
*/
public function peek($length = null)
{
}
/**
* @return mixed
*/
public function recv($length = null, $timeout = null)
{
}
/**
* @return mixed
*/
public function recvPacket($timeout = null)
{
}
/**
* @return mixed
*/
public function send($data, $timeout = null)
{
}
/**
* @return mixed
*/
public function sendFile($filename, $offset = null, $length = null)
{
}
/**
* @return mixed
*/
public function recvAll($length = null, $timeout = null)
{
}
/**
* @return mixed
*/
public function sendAll($data, $timeout = null)
{
}
/**
* @return mixed
*/
public function recvfrom(&$peername, $timeout = null)
{
}
/**
* @return mixed
*/
public function sendto($addr, $port, $data)
{
}
/**
* @return mixed
*/
public function getOption($level, $opt_name)
{
}
/**
* @return mixed
*/
public function setProtocol(array $settings)
{
}
/**
* @return mixed
*/
public function setOption($level, $opt_name, $opt_value)
{
}
/**
* @return mixed
*/
public function sslHandshake()
{
}
/**
* @return mixed
*/
public function shutdown($how = null)
{
}
/**
* @return mixed
*/
public function cancel($event = null)
{
}
/**
* @return mixed
*/
public function close()
{
}
/**
* @return mixed
*/
public function getpeername()
{
}
/**
* @return mixed
*/
public function getsockname()
{
}
}
@@ -0,0 +1,9 @@
<?php
namespace Swoole\Coroutine\Socket;
class Exception extends \Swoole\Exception
{
}
@@ -0,0 +1,114 @@
<?php
namespace Swoole\Coroutine;
class System
{
/**
* @return mixed
*/
public static function gethostbyname($domain_name, $family = null, $timeout = null)
{
}
/**
* @return mixed
*/
public static function dnsLookup($domain_name, $timeout = null)
{
}
/**
* @return mixed
*/
public static function exec($command, $get_error_stream = null)
{
}
/**
* @return mixed
*/
public static function sleep($seconds)
{
}
/**
* @return mixed
*/
public static function getaddrinfo($hostname, $family = null, $socktype = null, $protocol = null, $service = null, $timeout = null)
{
}
/**
* @return mixed
*/
public static function statvfs($path)
{
}
/**
* @return mixed
*/
public static function readFile($filename)
{
}
/**
* @return mixed
*/
public static function writeFile($filename, $data, $flags = null)
{
}
/**
* @return mixed
*/
public static function wait($timeout = null)
{
}
/**
* @return mixed
*/
public static function waitPid($pid, $timeout = null)
{
}
/**
* @return mixed
*/
public static function waitSignal($signo, $timeout = null)
{
}
/**
* @return mixed
*/
public static function waitEvent($fd, $events = null, $timeout = null)
{
}
/**
* @return mixed
*/
public static function fread($handle, $length = null)
{
}
/**
* @return mixed
*/
public static function fwrite($handle, $string, $length = null)
{
}
/**
* @return mixed
*/
public static function fgets($handle)
{
}
}
@@ -0,0 +1,9 @@
<?php
namespace Swoole;
class Error extends \Error
{
}
@@ -0,0 +1,86 @@
<?php
namespace Swoole;
class Event
{
/**
* @return mixed
*/
public static function add($fd, ?callable $read_callback, ?callable $write_callback = null, $events = null)
{
}
/**
* @return mixed
*/
public static function del($fd)
{
}
/**
* @return mixed
*/
public static function set($fd, ?callable $read_callback = null, ?callable $write_callback = null, $events = null)
{
}
/**
* @return mixed
*/
public static function isset($fd, $events = null)
{
}
/**
* @return mixed
*/
public static function dispatch()
{
}
/**
* @return mixed
*/
public static function defer(callable $callback)
{
}
/**
* @return mixed
*/
public static function cycle(?callable $callback, $before = null)
{
}
/**
* @return mixed
*/
public static function write($fd, $data)
{
}
/**
* @return mixed
*/
public static function wait()
{
}
/**
* @return mixed
*/
public static function rshutdown()
{
}
/**
* @return mixed
*/
public static function exit()
{
}
}
@@ -0,0 +1,9 @@
<?php
namespace Swoole;
class Exception extends \Exception
{
}
@@ -0,0 +1,27 @@
<?php
namespace Swoole;
class ExitException extends Exception
{
private $flags = 0;
private $status = 0;
/**
* @return mixed
*/
public function getFlags()
{
}
/**
* @return mixed
*/
public function getStatus()
{
}
}
@@ -0,0 +1,52 @@
<?php
namespace Swoole\Http;
class Request
{
public $fd = 0;
public $streamId = 0;
public $header;
public $server;
public $cookie;
public $get;
public $files;
public $post;
public $tmpfiles;
/**
* @return mixed
*/
public function rawContent()
{
}
/**
* @return mixed
*/
public function getContent()
{
}
/**
* @return mixed
*/
public function getData()
{
}
public function __destruct()
{
}
}
@@ -0,0 +1,170 @@
<?php
namespace Swoole\Http;
class Response
{
public $fd = 0;
public $socket;
public $header;
public $cookie;
public $trailer;
/**
* @return mixed
*/
public function initHeader()
{
}
/**
* @return mixed
*/
public function cookie($name, $value = null, $expires = null, $path = null, $domain = null, $secure = null, $httponly = null, $samesite = null)
{
}
/**
* @return mixed
*/
public function setCookie($name, $value = null, $expires = null, $path = null, $domain = null, $secure = null, $httponly = null, $samesite = null)
{
}
/**
* @return mixed
*/
public function rawcookie($name, $value = null, $expires = null, $path = null, $domain = null, $secure = null, $httponly = null, $samesite = null)
{
}
/**
* @return mixed
*/
public function status($http_code, $reason = null)
{
}
/**
* @return mixed
*/
public function setStatusCode($http_code, $reason = null)
{
}
/**
* @return mixed
*/
public function header($key, $value, $ucwords = null)
{
}
/**
* @return mixed
*/
public function setHeader($key, $value, $ucwords = null)
{
}
/**
* @return mixed
*/
public function trailer($key, $value)
{
}
/**
* @return mixed
*/
public function ping()
{
}
/**
* @return mixed
*/
public function goaway()
{
}
/**
* @return mixed
*/
public function write($content)
{
}
/**
* @return mixed
*/
public function end($content = null)
{
}
/**
* @return mixed
*/
public function sendfile($filename, $offset = null, $length = null)
{
}
/**
* @return mixed
*/
public function redirect($location, $http_code = null)
{
}
/**
* @return mixed
*/
public function detach()
{
}
/**
* @return mixed
*/
public static function create($server, $fd = null)
{
}
/**
* @return mixed
*/
public function upgrade()
{
}
/**
* @return mixed
*/
public function push($data, $opcode = null, $flags = null)
{
}
/**
* @return mixed
*/
public function recv()
{
}
/**
* @return mixed
*/
public function close()
{
}
public function __destruct()
{
}
}
@@ -0,0 +1,9 @@
<?php
namespace Swoole\Http;
class Server extends \Swoole\Server
{
}
@@ -0,0 +1,21 @@
<?php
namespace Swoole\Http2;
class Request
{
public $path = '/';
public $method = 'GET';
public $headers;
public $cookies;
public $data = '';
public $pipeline = false;
}
@@ -0,0 +1,25 @@
<?php
namespace Swoole\Http2;
class Response
{
public $streamId = 0;
public $errCode = 0;
public $statusCode = 0;
public $pipeline = false;
public $headers;
public $set_cookie_headers;
public $cookies;
public $data;
}
@@ -0,0 +1,78 @@
<?php
namespace Swoole;
class Lock
{
public const FILELOCK = 2;
public const MUTEX = 3;
public const SEM = 4;
public const RWLOCK = 1;
public const SPINLOCK = 5;
public $errCode = 0;
public function __construct($type = null, $filename = null)
{
}
public function __destruct()
{
}
/**
* @return mixed
*/
public function lock()
{
}
/**
* @return mixed
*/
public function lockwait($timeout = null)
{
}
/**
* @return mixed
*/
public function trylock()
{
}
/**
* @return mixed
*/
public function lock_read()
{
}
/**
* @return mixed
*/
public function trylock_read()
{
}
/**
* @return mixed
*/
public function unlock()
{
}
/**
* @return mixed
*/
public function destroy()
{
}
}
@@ -0,0 +1,193 @@
<?php
namespace Swoole;
class Process
{
public const IPC_NOWAIT = 256;
public const PIPE_MASTER = 1;
public const PIPE_WORKER = 2;
public const PIPE_READ = 3;
public const PIPE_WRITE = 4;
public $pipe;
public $msgQueueId;
public $msgQueueKey;
public $pid;
public $id;
private $callback;
public function __construct(callable $callback, $redirect_stdin_and_stdout = null, $pipe_type = null, $enable_coroutine = null)
{
}
public function __destruct()
{
}
/**
* @return mixed
*/
public static function wait($blocking = null)
{
}
/**
* @return mixed
*/
public static function signal($signal_no, $callback)
{
}
/**
* @return mixed
*/
public static function alarm($usec, $type = null)
{
}
/**
* @return mixed
*/
public static function kill($pid, $signal_no = null)
{
}
/**
* @return mixed
*/
public static function daemon($nochdir = null, $noclose = null, $pipes = null)
{
}
/**
* @return mixed
*/
public static function setaffinity(array $cpu_settings)
{
}
/**
* @return mixed
*/
public function set(array $settings)
{
}
/**
* @return mixed
*/
public function setTimeout($seconds)
{
}
/**
* @return mixed
*/
public function setBlocking($blocking)
{
}
/**
* @return mixed
*/
public function useQueue($key = null, $mode = null, $capacity = null)
{
}
/**
* @return mixed
*/
public function statQueue()
{
}
/**
* @return mixed
*/
public function freeQueue()
{
}
/**
* @return mixed
*/
public function start()
{
}
/**
* @return mixed
*/
public function write($data)
{
}
/**
* @return mixed
*/
public function close()
{
}
/**
* @return mixed
*/
public function read($size = null)
{
}
/**
* @return mixed
*/
public function push($data)
{
}
/**
* @return mixed
*/
public function pop($size = null)
{
}
/**
* @return mixed
*/
public function exit($exit_code = null)
{
}
/**
* @return mixed
*/
public function exec($exec_file, $args)
{
}
/**
* @return mixed
*/
public function exportSocket()
{
}
/**
* @return mixed
*/
public function name($process_name)
{
}
}
@@ -0,0 +1,70 @@
<?php
namespace Swoole\Process;
class Pool
{
public $master_pid = -1;
public $workers;
public function __construct($worker_num, $ipc_type = null, $msgqueue_key = null, $enable_coroutine = null)
{
}
public function __destruct()
{
}
/**
* @return mixed
*/
public function set(array $settings)
{
}
/**
* @return mixed
*/
public function on($event_name, callable $callback)
{
}
/**
* @return mixed
*/
public function getProcess($worker_id = null)
{
}
/**
* @return mixed
*/
public function listen($host, $port = null, $backlog = null)
{
}
/**
* @return mixed
*/
public function write($data)
{
}
/**
* @return mixed
*/
public function start()
{
}
/**
* @return mixed
*/
public function shutdown()
{
}
}
@@ -0,0 +1,51 @@
<?php
namespace Swoole\Redis;
class Server extends \Swoole\Server
{
public const NIL = 1;
public const ERROR = 0;
public const STATUS = 2;
public const INT = 3;
public const STRING = 4;
public const SET = 5;
public const MAP = 6;
/**
* @return mixed
*/
public function start()
{
}
/**
* @return mixed
*/
public function setHandler($command, callable $callback)
{
}
/**
* @return mixed
*/
public function getHandler($command)
{
}
/**
* @return mixed
*/
public static function format($type, $value = null)
{
}
}
@@ -0,0 +1,30 @@
<?php
namespace Swoole;
class Runtime
{
/**
* @return mixed
*/
public static function enableCoroutine($enable = null, $flags = null)
{
}
/**
* @return mixed
*/
public static function getHookFlags()
{
}
/**
* @return mixed
*/
public static function setHookFlags($flags)
{
}
}
@@ -0,0 +1,356 @@
<?php
namespace Swoole;
class Server
{
private $onStart;
private $onShutdown;
private $onWorkerStart;
private $onWorkerStop;
private $onBeforeReload;
private $onAfterReload;
private $onWorkerExit;
private $onWorkerError;
private $onTask;
private $onFinish;
private $onManagerStart;
private $onManagerStop;
private $onPipeMessage;
public $setting;
public $connections;
public $host = '';
public $port = 0;
public $type = 0;
public $mode = 0;
public $ports;
public $master_pid = 0;
public $manager_pid = 0;
public $worker_id = -1;
public $taskworker = false;
public $worker_pid = 0;
public $stats_timer;
public function __construct($host, $port = null, $mode = null, $sock_type = null)
{
}
public function __destruct()
{
}
/**
* @return mixed
*/
public function listen($host, $port, $sock_type)
{
}
/**
* @return mixed
*/
public function addlistener($host, $port, $sock_type)
{
}
/**
* @return mixed
*/
public function on($event_name, callable $callback)
{
}
/**
* @return mixed
*/
public function getCallback($event_name)
{
}
/**
* @return mixed
*/
public function set(array $settings)
{
}
/**
* @return mixed
*/
public function start()
{
}
/**
* @return mixed
*/
public function send($fd, $send_data, $server_socket = null)
{
}
/**
* @return mixed
*/
public function sendto($ip, $port, $send_data, $server_socket = null)
{
}
/**
* @return mixed
*/
public function sendwait($conn_fd, $send_data)
{
}
/**
* @return mixed
*/
public function exists($fd)
{
}
/**
* @return mixed
*/
public function exist($fd)
{
}
/**
* @return mixed
*/
public function protect($fd, $is_protected = null)
{
}
/**
* @return mixed
*/
public function sendfile($conn_fd, $filename, $offset = null, $length = null)
{
}
/**
* @return mixed
*/
public function close($fd, $reset = null)
{
}
/**
* @return mixed
*/
public function confirm($fd)
{
}
/**
* @return mixed
*/
public function pause($fd)
{
}
/**
* @return mixed
*/
public function resume($fd)
{
}
/**
* @return mixed
*/
public function task($data, $worker_id = null, ?callable $finish_callback = null)
{
}
/**
* @return mixed
*/
public function taskwait($data, $timeout = null, $worker_id = null)
{
}
/**
* @return mixed
*/
public function taskWaitMulti(array $tasks, $timeout = null)
{
}
/**
* @return mixed
*/
public function taskCo(array $tasks, $timeout = null)
{
}
/**
* @return mixed
*/
public function finish($data)
{
}
/**
* @return mixed
*/
public function reload()
{
}
/**
* @return mixed
*/
public function shutdown()
{
}
/**
* @return mixed
*/
public function stop($worker_id = null)
{
}
/**
* @return mixed
*/
public function getLastError()
{
}
/**
* @return mixed
*/
public function heartbeat($reactor_id)
{
}
/**
* @return mixed
*/
public function getClientInfo($fd, $reactor_id = null)
{
}
/**
* @return mixed
*/
public function getClientList($start_fd, $find_count = null)
{
}
/**
* @return mixed
*/
public function getWorkerId()
{
}
/**
* @return mixed
*/
public function getWorkerPid()
{
}
/**
* @return mixed
*/
public function getWorkerStatus($worker_id = null)
{
}
/**
* @return mixed
*/
public function getManagerPid()
{
}
/**
* @return mixed
*/
public function getMasterPid()
{
}
/**
* @return mixed
*/
public function connection_info($fd, $reactor_id = null)
{
}
/**
* @return mixed
*/
public function connection_list($start_fd, $find_count = null)
{
}
/**
* @return mixed
*/
public function sendMessage($message, $dst_worker_id)
{
}
/**
* @return mixed
*/
public function addProcess(\swoole_process $process)
{
}
/**
* @return mixed
*/
public function stats()
{
}
/**
* @return mixed
*/
public function getSocket($port = null)
{
}
/**
* @return mixed
*/
public function bind($fd, $uid)
{
}
}
@@ -0,0 +1,77 @@
<?php
namespace Swoole\Server;
class Port
{
private $onConnect;
private $onReceive;
private $onClose;
private $onPacket;
private $onBufferFull;
private $onBufferEmpty;
private $onRequest;
private $onHandShake;
private $onOpen;
private $onMessage;
public $host;
public $port = 0;
public $type = 0;
public $sock = -1;
public $setting;
public $connections;
private function __construct()
{
}
public function __destruct()
{
}
/**
* @return mixed
*/
public function set(array $settings)
{
}
/**
* @return mixed
*/
public function on($event_name, callable $callback)
{
}
/**
* @return mixed
*/
public function getCallback($event_name)
{
}
/**
* @return mixed
*/
public function getSocket()
{
}
}
@@ -0,0 +1,31 @@
<?php
namespace Swoole\Server;
class Task
{
public $data;
public $id = -1;
public $worker_id = -1;
public $flags = 0;
/**
* @return mixed
*/
public function finish($data)
{
}
/**
* @return mixed
*/
public static function pack($data)
{
}
}
@@ -0,0 +1,173 @@
<?php
namespace Swoole;
class Table implements \Iterator, \ArrayAccess
{
public const TYPE_INT = 1;
public const TYPE_STRING = 3;
public const TYPE_FLOAT = 2;
public function __construct($table_size, $conflict_proportion = null)
{
}
/**
* @return mixed
*/
public function column($name, $type, $size = null)
{
}
/**
* @return mixed
*/
public function create()
{
}
/**
* @return mixed
*/
public function destroy()
{
}
/**
* @return mixed
*/
public function set($key, array $value)
{
}
/**
* @return mixed
*/
public function get($key, $field = null)
{
}
/**
* @return mixed
*/
public function count()
{
}
/**
* @return mixed
*/
public function del($key)
{
}
/**
* @return mixed
*/
public function delete($key)
{
}
/**
* @return mixed
*/
public function exists($key)
{
}
/**
* @return mixed
*/
public function exist($key)
{
}
/**
* @return mixed
*/
public function incr($key, $column, $incrby = null)
{
}
/**
* @return mixed
*/
public function decr($key, $column, $decrby = null)
{
}
/**
* @return mixed
*/
public function getMemorySize()
{
}
/**
* @return mixed
*/
public function offsetExists($offset)
{
}
/**
* @return mixed
*/
public function offsetGet($offset)
{
}
/**
* @return mixed
*/
public function offsetSet($offset, $value)
{
}
/**
* @return mixed
*/
public function offsetUnset($offset)
{
}
/**
* @return mixed
*/
public function rewind()
{
}
/**
* @return mixed
*/
public function next()
{
}
/**
* @return mixed
*/
public function current()
{
}
/**
* @return mixed
*/
public function key()
{
}
/**
* @return mixed
*/
public function valid()
{
}
}
@@ -0,0 +1,45 @@
<?php
namespace Swoole\Table;
class Row implements \ArrayAccess
{
public $key;
public $value;
/**
* @return mixed
*/
public function offsetExists($offset)
{
}
/**
* @return mixed
*/
public function offsetGet($offset)
{
}
/**
* @return mixed
*/
public function offsetSet($offset, $value)
{
}
/**
* @return mixed
*/
public function offsetUnset($offset)
{
}
public function __destruct()
{
}
}
@@ -0,0 +1,72 @@
<?php
namespace Swoole;
class Timer
{
/**
* @return mixed
*/
public static function set(array $settings)
{
}
/**
* @return mixed
*/
public static function tick($ms, callable $callback, ... $params)
{
}
/**
* @return mixed
*/
public static function after($ms, callable $callback, ... $params)
{
}
/**
* @return mixed
*/
public static function exists($timer_id)
{
}
/**
* @return mixed
*/
public static function info($timer_id)
{
}
/**
* @return mixed
*/
public static function stats()
{
}
/**
* @return mixed
*/
public static function list()
{
}
/**
* @return mixed
*/
public static function clear($timer_id)
{
}
/**
* @return mixed
*/
public static function clearAll()
{
}
}
@@ -0,0 +1,13 @@
<?php
namespace Swoole\Timer;
class Iterator extends \ArrayIterator
{
public const STD_PROP_LIST = 1;
public const ARRAY_AS_PROPS = 2;
}
@@ -0,0 +1,15 @@
<?php
namespace Swoole\WebSocket;
class CloseFrame extends Frame
{
public $opcode = 8;
public $code = 1000;
public $reason = '';
}
@@ -0,0 +1,40 @@
<?php
namespace Swoole\WebSocket;
class Frame
{
public $fd = 0;
public $data = '';
public $opcode = 1;
public $flags = 1;
public $finish;
/**
* @return mixed
*/
public function __toString()
{
}
/**
* @return mixed
*/
public static function pack($data, $opcode = null, $flags = null)
{
}
/**
* @return mixed
*/
public static function unpack($data)
{
}
}
@@ -0,0 +1,44 @@
<?php
namespace Swoole\WebSocket;
class Server extends \Swoole\Http\Server
{
/**
* @return mixed
*/
public function push($fd, $data, $opcode = null, $flags = null)
{
}
/**
* @return mixed
*/
public function disconnect($fd, $code = null, $reason = null)
{
}
/**
* @return mixed
*/
public function isEstablished($fd)
{
}
/**
* @return mixed
*/
public static function pack($data, $opcode = null, $flags = null)
{
}
/**
* @return mixed
*/
public static function unpack($data)
{
}
}
@@ -0,0 +1,21 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
if (SWOOLE_USE_SHORTNAME) {
class_alias(Swoole\Coroutine\WaitGroup::class, Co\WaitGroup::class, true);
class_alias(Swoole\Coroutine\Server::class, Co\Server::class, true);
class_alias(Swoole\Coroutine\Server\Connection::class, Co\Server\Connection::class, true);
class_alias(Swoole\Coroutine\FastCGI\Client::class, Co\FastCGI\Client::class, true);
class_alias(Swoole\Coroutine\FastCGI\Client\Exception::class, Co\FastCGI\Client\Exception::class, true);
class_alias(Swoole\Coroutine\FastCGI\Proxy::class, Co\FastCGI\Proxy::class, true);
}
class_alias(Swoole\Process\Manager::class, Swoole\Process\ProcessManager::class, true);
@@ -0,0 +1,28 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\Coroutine {
function run(callable $fn, ...$args)
{
$s = new Scheduler();
$s->add($fn, ...$args);
return $s->start();
}
}
namespace Co {
if (SWOOLE_USE_SHORTNAME) {
function run(callable $fn, ...$args)
{
return \Swoole\Coroutine\Run($fn, ...$args);
}
}
}
@@ -0,0 +1,681 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole;
use ArrayAccess;
use Countable;
use Iterator;
use RuntimeException;
use Serializable;
use Swoole\Exception\ArrayKeyNotExists;
class ArrayObject implements ArrayAccess, Serializable, Countable, Iterator
{
/**
* @var array
*/
protected $array;
/**
* ArrayObject constructor.
*/
public function __construct(array $array = [])
{
$this->array = $array;
}
public function __toArray(): array
{
return $this->array;
}
public function toArray(): array
{
return $this->array;
}
public function isEmpty(): bool
{
return empty($this->array);
}
public function count(): int
{
return count($this->array);
}
/**
* @return mixed
*/
public function current()
{
return current($this->array);
}
/**
* @return mixed
*/
public function key()
{
return key($this->array);
}
public function valid(): bool
{
return array_key_exists($this->key(), $this->array);
}
/**
* @return mixed
*/
public function rewind()
{
return reset($this->array);
}
/**
* @return mixed
*/
public function next()
{
return next($this->array);
}
/**
* @param mixed $key
* @return ArrayObject|StringObject
*/
public function get($key)
{
if (!$this->exists($key)) {
throw new ArrayKeyNotExists($key);
}
return static::detectType($this->array[$key]);
}
/**
* @return mixed
*/
public function last()
{
$key = array_key_last($this->array);
if ($key === null) {
return null;
}
return $this->get($key);
}
/**
* @return null|int|string
*/
public function firstKey()
{
return array_key_first($this->array);
}
/**
* @return null|int|string
*/
public function lastKey()
{
return array_key_last($this->array);
}
/**
* @return mixed
*/
public function first()
{
$key = array_key_first($this->array);
if ($key === null) {
return null;
}
return $this->get($key);
}
/**
* @param mixed $key
* @param mixed $value
* @return $this
*/
public function set($key, $value): self
{
$this->array[$key] = $value;
return $this;
}
/**
* @param mixed $key
* @return $this
*/
public function delete($key): self
{
unset($this->array[$key]);
return $this;
}
/**
* @param mixed $value
* @return $this
*/
public function remove($value, bool $strict = true, bool $loop = false): self
{
do {
$key = $this->search($value, $strict);
if ($key === false) {
break;
}
unset($this->array[$key]);
} while ($loop);
return $this;
}
/**
* @return $this
*/
public function clear(): self
{
$this->array = [];
return $this;
}
/**
* @param mixed $key
* @return null|mixed
*/
public function offsetGet($key)
{
if (!array_key_exists($key, $this->array)) {
return null;
}
return $this->array[$key];
}
/**
* @param mixed $key
* @param mixed $value
*/
public function offsetSet($key, $value): void
{
$this->array[$key] = $value;
}
/**
* @param mixed $key
*/
public function offsetUnset($key): void
{
unset($this->array[$key]);
}
/**
* @param mixed $key
* @return bool
*/
public function offsetExists($key)
{
return isset($this->array[$key]);
}
/**
* @param mixed $key
*/
public function exists($key): bool
{
return array_key_exists($key, $this->array);
}
/**
* @param mixed $value
*/
public function contains($value, bool $strict = true): bool
{
return in_array($value, $this->array, $strict);
}
/**
* @param mixed $value
* @return mixed
*/
public function indexOf($value, bool $strict = true)
{
return $this->search($value, $strict);
}
/**
* @param mixed $value
* @return mixed
*/
public function lastIndexOf($value, bool $strict = true)
{
$array = $this->array;
for (end($array); ($currentKey = key($array)) !== null; prev($array)) {
$currentValue = current($array);
if ($currentValue == $value) {
if ($strict && $currentValue !== $value) {
continue;
}
break;
}
}
return $currentKey;
}
/**
* @param mixed $needle
* @return mixed
*/
public function search($needle, bool $strict = true)
{
return array_search($needle, $this->array, $strict);
}
public function join(string $glue = ''): StringObject
{
return static::detectStringType(implode($glue, $this->array));
}
public function serialize(): StringObject
{
return static::detectStringType(serialize($this->array));
}
/**
* @param string $string
* @return $this
*/
public function unserialize($string): self
{
$this->array = (array) unserialize((string) $string);
return $this;
}
/**
* @return float|int
*/
public function sum()
{
return array_sum($this->array);
}
/**
* @return float|int
*/
public function product()
{
return array_product($this->array);
}
/**
* @param mixed $value
* @return int
*/
public function push($value)
{
return $this->pushBack($value);
}
/**
* @param mixed $value
* @return int
*/
public function pushFront($value)
{
return array_unshift($this->array, $value);
}
public function append(...$values): ArrayObject
{
array_push($this->array, ...$values);
return $this;
}
/**
* @param mixed $value
* @return int
*/
public function pushBack($value)
{
return array_push($this->array, $value);
}
/**
* @param mixed $value
* @return $this
*/
public function insert(int $offset, $value): self
{
if (is_array($value) || is_object($value) || is_null($value)) {
$value = [$value];
}
array_splice($this->array, $offset, 0, $value);
return $this;
}
/**
* @return mixed
*/
public function pop()
{
return $this->popBack();
}
/**
* @return mixed
*/
public function popFront()
{
return array_shift($this->array);
}
/**
* @return mixed
*/
public function popBack()
{
return array_pop($this->array);
}
/**
* @param mixed $offset
* @param int $length
* @return static
*/
public function slice($offset, int $length = null, bool $preserve_keys = false): self
{
return new static(array_slice($this->array, ...func_get_args()));
}
/**
* @return ArrayObject|mixed|StringObject
*/
public function randomGet()
{
return static::detectType($this->array[array_rand($this->array, 1)]);
}
/**
* @return $this
*/
public function each(callable $fn): self
{
if (array_walk($this->array, $fn) === false) {
throw new RuntimeException('array_walk() failed');
}
return $this;
}
/**
* @param array $args
* @return static
*/
public function map(callable $fn, ...$args): self
{
return new static(array_map($fn, $this->array, ...$args));
}
/**
* @param null $initial
* @return mixed
*/
public function reduce(callable $fn, $initial = null)
{
return array_reduce($this->array, $fn, $initial);
}
/**
* @param array $args
* @return static
*/
public function keys(...$args): self
{
return new static(array_keys($this->array, ...$args));
}
/**
* @return static
*/
public function values(): self
{
return new static(array_values($this->array));
}
/**
* @param mixed $column_key
* @param mixed $index
* @return static
*/
public function column($column_key, $index = null): self
{
return new static(array_column($this->array, $column_key, $index));
}
/**
* @return static
*/
public function unique(int $sort_flags = SORT_STRING): self
{
return new static(array_unique($this->array, $sort_flags));
}
/**
* @return static
*/
public function reverse(bool $preserve_keys = false): self
{
return new static(array_reverse($this->array, $preserve_keys));
}
/**
* @return static
*/
public function chunk(int $size, bool $preserve_keys = false): self
{
return new static(array_chunk($this->array, $size, $preserve_keys));
}
/**
* Swap keys and values in an array.
* @return static
*/
public function flip(): self
{
return new static(array_flip($this->array));
}
/**
* @return static
*/
public function filter(callable $fn, int $flag = 0): self
{
return new static(array_filter($this->array, $fn, $flag));
}
/**
* | Function name | Sorts by | Maintains key association | Order of sort | Related functions |
* | :---------------- | :------- | :-------------------------- | :-------------------------- | :---------------- |
* | array_multisort() | value | associative yes, numeric no | first array or sort options | array_walk() |
* | asort() | value | yes | low to high | arsort() |
* | arsort() | value | yes | high to low | asort() |
* | krsort() | key | yes | high to low | ksort() |
* | ksort() | key | yes | low to high | asort() |
* | natcasesort() | value | yes | natural, case insensitive | natsort() |
* | natsort() | value | yes | natural | natcasesort() |
* | rsort() | value | no | high to low | sort() |
* | shuffle() | value | no | random | array_rand() |
* | sort() | value | no | low to high | rsort() |
* | uasort() | value | yes | user defined | uksort() |
* | uksort() | key | yes | user defined | uasort() |
* | usort() | value | no | user defined | uasort() |
*/
/**
* @return $this
*/
public function asort(int $sort_flags = SORT_REGULAR): self
{
if (asort($this->array, $sort_flags) !== true) {
throw new RuntimeException('asort() failed');
}
return $this;
}
/**
* @return $this
*/
public function arsort(int $sort_flags = SORT_REGULAR): self
{
if (arsort($this->array, $sort_flags) !== true) {
throw new RuntimeException('arsort() failed');
}
return $this;
}
/**
* @return $this
*/
public function krsort(int $sort_flags = SORT_REGULAR): self
{
if (krsort($this->array, $sort_flags) !== true) {
throw new RuntimeException('krsort() failed');
}
return $this;
}
/**
* @return $this
*/
public function ksort(int $sort_flags = SORT_REGULAR): self
{
if (ksort($this->array, $sort_flags) !== true) {
throw new RuntimeException('ksort() failed');
}
return $this;
}
/**
* @return $this
*/
public function natcasesort(): self
{
if (natcasesort($this->array) !== true) {
throw new RuntimeException('natcasesort() failed');
}
return $this;
}
/**
* @return $this
*/
public function natsort(): self
{
if (natsort($this->array) !== true) {
throw new RuntimeException('natsort() failed');
}
return $this;
}
/**
* @return $this
*/
public function rsort(int $sort_flags = SORT_REGULAR): self
{
if (rsort($this->array, $sort_flags) !== true) {
throw new RuntimeException('rsort() failed');
}
return $this;
}
/**
* @return $this
*/
public function shuffle(): self
{
if (shuffle($this->array) !== true) {
throw new RuntimeException('shuffle() failed');
}
return $this;
}
/**
* @return $this
*/
public function sort(int $sort_flags = SORT_REGULAR): self
{
if (sort($this->array, $sort_flags) !== true) {
throw new RuntimeException('sort() failed');
}
return $this;
}
/**
* @return $this
*/
public function uasort(callable $value_compare_func): self
{
if (uasort($this->array, $value_compare_func) !== true) {
throw new RuntimeException('uasort() failed');
}
return $this;
}
/**
* @return $this
*/
public function uksort(callable $value_compare_func): self
{
if (uksort($this->array, $value_compare_func) !== true) {
throw new RuntimeException('uksort() failed');
}
return $this;
}
/**
* @return $this
*/
public function usort(callable $value_compare_func): self
{
if (usort($this->array, $value_compare_func) !== true) {
throw new RuntimeException('usort() failed');
}
return $this;
}
/**
* @param mixed $value
* @return ArrayObject|mixed|StringObject
*/
protected static function detectType($value)
{
if (is_string($value)) {
return static::detectStringType($value);
}
if (is_array($value)) {
return static::detectArrayType($value);
}
return $value;
}
protected static function detectStringType(string $value): StringObject
{
return new StringObject($value);
}
/**
* @return static
*/
protected static function detectArrayType(array $value): self
{
return new static($value);
}
}
@@ -0,0 +1,100 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole;
use RuntimeException;
use Swoole\Coroutine\Channel;
use Throwable;
class ConnectionPool
{
public const DEFAULT_SIZE = 64;
/** @var Channel */
protected $pool;
/** @var callable */
protected $constructor;
/** @var int */
protected $size;
/** @var int */
protected $num;
/** @var null|string */
protected $proxy;
public function __construct(callable $constructor, int $size = self::DEFAULT_SIZE, ?string $proxy = null)
{
$this->pool = new Channel($this->size = $size);
$this->constructor = $constructor;
$this->num = 0;
$this->proxy = $proxy;
}
public function fill(): void
{
while ($this->size > $this->num) {
$this->make();
}
}
public function get()
{
if ($this->pool === null) {
throw new RuntimeException('Pool has been closed');
}
if ($this->pool->isEmpty() && $this->num < $this->size) {
$this->make();
}
return $this->pool->pop();
}
public function put($connection): void
{
if ($this->pool === null) {
return;
}
if ($connection !== null) {
$this->pool->push($connection);
} else {
/* connection broken */
$this->num -= 1;
$this->make();
}
}
public function close(): void
{
$this->pool->close();
$this->pool = null;
$this->num = 0;
}
protected function make(): void
{
$this->num++;
try {
if ($this->proxy) {
$connection = new $this->proxy($this->constructor);
} else {
$constructor = $this->constructor;
$connection = $constructor();
}
} catch (Throwable $throwable) {
$this->num--;
throw $throwable;
}
$this->put($connection);
}
}
@@ -0,0 +1,404 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole;
class Constant
{
public const EVENT_RECEIVE = 'receive';
public const EVENT_CONNECT = 'connect';
public const EVENT_CLOSE = 'close';
public const EVENT_PACKET = 'packet';
public const EVENT_REQUEST = 'request';
public const EVENT_MESSAGE = 'message';
public const EVENT_OPEN = 'open';
public const EVENT_HANDSHAKE = 'handshake';
public const EVENT_TASK = 'task';
public const EVENT_FINISH = 'finish';
public const EVENT_START = 'start';
public const EVENT_SHUTDOWN = 'shutdown';
public const EVENT_WORKER_START = 'workerStart';
public const EVENT_WORKER_EXIT = 'workerExit';
public const EVENT_WORKER_ERROR = 'workerError';
public const EVENT_WORKER_STOP = 'workerStop';
public const EVENT_PIPE_MESSAGE = 'pipeMessage';
public const EVENT_MANAGER_START = 'managerStart';
public const EVENT_MANAGER_STOP = 'managerStop';
public const EVENT_ERROR = 'error';
/* {{{ OPTION */
public const OPTION_DEBUG_MODE = 'debug_mode';
public const OPTION_TRACE_FLAGS = 'trace_flags';
public const OPTION_LOG_FILE = 'log_file';
public const OPTION_LOG_LEVEL = 'log_level';
public const OPTION_LOG_DATE_FORMAT = 'log_date_format';
public const OPTION_LOG_DATE_WITH_MICROSECONDS = 'log_date_with_microseconds';
public const OPTION_LOG_ROTATION = 'log_rotation';
public const OPTION_DISPLAY_ERRORS = 'display_errors';
public const OPTION_DNS_SERVER = 'dns_server';
public const OPTION_SOCKET_DNS_TIMEOUT = 'socket_dns_timeout';
public const OPTION_SOCKET_CONNECT_TIMEOUT = 'socket_connect_timeout';
public const OPTION_SOCKET_WRITE_TIMEOUT = 'socket_write_timeout';
public const OPTION_SOCKET_SEND_TIMEOUT = 'socket_send_timeout';
public const OPTION_SOCKET_READ_TIMEOUT = 'socket_read_timeout';
public const OPTION_SOCKET_RECV_TIMEOUT = 'socket_recv_timeout';
public const OPTION_SOCKET_BUFFER_SIZE = 'socket_buffer_size';
public const OPTION_SOCKET_TIMEOUT = 'socket_timeout';
public const OPTION_ENABLE_SIGNALFD = 'enable_signalfd';
public const OPTION_WAIT_SIGNAL = 'wait_signal';
public const OPTION_DNS_CACHE_REFRESH_TIME = 'dns_cache_refresh_time';
public const OPTION_THREAD_NUM = 'thread_num';
public const OPTION_MIN_THREAD_NUM = 'min_thread_num';
public const OPTION_MAX_THREAD_NUM = 'max_thread_num';
public const OPTION_SOCKET_DONTWAIT = 'socket_dontwait';
public const OPTION_DNS_LOOKUP_RANDOM = 'dns_lookup_random';
public const OPTION_USE_ASYNC_RESOLVER = 'use_async_resolver';
public const OPTION_ENABLE_COROUTINE = 'enable_coroutine';
public const OPTION_SSL_PROTOCOLS = 'ssl_protocols';
public const OPTION_SSL_COMPRESS = 'ssl_compress';
public const OPTION_SSL_CERT_FILE = 'ssl_cert_file';
public const OPTION_SSL_KEY_FILE = 'ssl_key_file';
public const OPTION_SSL_PASSPHRASE = 'ssl_passphrase';
public const OPTION_SSL_HOST_NAME = 'ssl_host_name';
public const OPTION_SSL_VERIFY_PEER = 'ssl_verify_peer';
public const OPTION_SSL_ALLOW_SELF_SIGNED = 'ssl_allow_self_signed';
public const OPTION_SSL_CAFILE = 'ssl_cafile';
public const OPTION_SSL_CAPATH = 'ssl_capath';
public const OPTION_SSL_VERIFY_DEPTH = 'ssl_verify_depth';
public const OPTION_OPEN_EOF_CHECK = 'open_eof_check';
public const OPTION_OPEN_EOF_SPLIT = 'open_eof_split';
public const OPTION_PACKAGE_EOF = 'package_eof';
public const OPTION_OPEN_MQTT_PROTOCOL = 'open_mqtt_protocol';
public const OPTION_OPEN_LENGTH_CHECK = 'open_length_check';
public const OPTION_PACKAGE_LENGTH_TYPE = 'package_length_type';
public const OPTION_PACKAGE_LENGTH_OFFSET = 'package_length_offset';
public const OPTION_PACKAGE_BODY_OFFSET = 'package_body_offset';
public const OPTION_PACKAGE_LENGTH_FUNC = 'package_length_func';
public const OPTION_PACKAGE_MAX_LENGTH = 'package_max_length';
public const OPTION_BUFFER_HIGH_WATERMARK = 'buffer_high_watermark';
public const OPTION_BUFFER_LOW_WATERMARK = 'buffer_low_watermark';
public const OPTION_BIND_PORT = 'bind_port';
public const OPTION_BIND_ADDRESS = 'bind_address';
public const OPTION_OPEN_TCP_NODELAY = 'open_tcp_nodelay';
public const OPTION_SOCKS5_HOST = 'socks5_host';
public const OPTION_SOCKS5_PORT = 'socks5_port';
public const OPTION_SOCKS5_USERNAME = 'socks5_username';
public const OPTION_SOCKS5_PASSWORD = 'socks5_password';
public const OPTION_HTTP_PROXY_HOST = 'http_proxy_host';
public const OPTION_HTTP_PROXY_PORT = 'http_proxy_port';
public const OPTION_HTTP_PROXY_USERNAME = 'http_proxy_username';
public const OPTION_HTTP_PROXY_USER = 'http_proxy_user';
public const OPTION_HTTP_PROXY_PASSWORD = 'http_proxy_password';
public const OPTION_TIMEOUT = 'timeout';
public const OPTION_CONNECT_TIMEOUT = 'connect_timeout';
public const OPTION_READ_TIMEOUT = 'read_timeout';
public const OPTION_WRITE_TIMEOUT = 'write_timeout';
public const OPTION_SSL_DISABLE_COMPRESSION = 'ssl_disable_compression';
public const OPTION_MAX_COROUTINE = 'max_coroutine';
public const OPTION_HOOK_FLAGS = 'hook_flags';
public const OPTION_ENABLE_PREEMPTIVE_SCHEDULER = 'enable_preemptive_scheduler';
public const OPTION_C_STACK_SIZE = 'c_stack_size';
public const OPTION_STACK_SIZE = 'stack_size';
public const OPTION_DNS_CACHE_EXPIRE = 'dns_cache_expire';
public const OPTION_DNS_CACHE_CAPACITY = 'dns_cache_capacity';
public const OPTION_AIO_CORE_WORKER_NUM = 'aio_core_worker_num';
public const OPTION_AIO_WORKER_NUM = 'aio_worker_num';
public const OPTION_AIO_MAX_WAIT_TIME = 'aio_max_wait_time';
public const OPTION_AIO_MAX_IDLE_TIME = 'aio_max_idle_time';
public const OPTION_RECONNECT = 'reconnect';
public const OPTION_DEFER = 'defer';
public const OPTION_LOWERCASE_HEADER = 'lowercase_header';
public const OPTION_KEEP_ALIVE = 'keep_alive';
public const OPTION_WEBSOCKET_MASK = 'websocket_mask';
public const OPTION_WEBSOCKET_COMPRESSION = 'websocket_compression';
public const OPTION_HTTP_PARSE_COOKIE = 'http_parse_cookie';
public const OPTION_HTTP_PARSE_POST = 'http_parse_post';
public const OPTION_HTTP_PARSE_FILES = 'http_parse_files';
public const OPTION_HTTP_COMPRESSION = 'http_compression';
public const OPTION_HTTP_COMPRESSION_LEVEL = 'http_compression_level';
public const OPTION_HTTP_GZIP_LEVEL = 'http_gzip_level';
public const OPTION_UPLOAD_TMP_DIR = 'upload_tmp_dir';
public const OPTION_HOST = 'host';
public const OPTION_PORT = 'port';
public const OPTION_SSL = 'ssl';
public const OPTION_USER = 'user';
public const OPTION_PASSWORD = 'password';
public const OPTION_DATABASE = 'database';
public const OPTION_CHARSET = 'charset';
public const OPTION_STRICT_TYPE = 'strict_type';
public const OPTION_FETCH_MODE = 'fetch_mode';
public const OPTION_SERIALIZE = 'serialize';
public const OPTION_COMPATIBILITY_MODE = 'compatibility_mode';
public const OPTION_CHROOT = 'chroot';
public const OPTION_GROUP = 'group';
public const OPTION_DAEMONIZE = 'daemonize';
public const OPTION_PID_FILE = 'pid_file';
public const OPTION_REACTOR_NUM = 'reactor_num';
public const OPTION_SINGLE_THREAD = 'single_thread';
public const OPTION_WORKER_NUM = 'worker_num';
public const OPTION_MAX_WAIT_TIME = 'max_wait_time';
public const OPTION_MAX_QUEUED_BYTES = 'max_queued_bytes';
public const OPTION_MAX_CORO_NUM = 'max_coro_num';
public const OPTION_SEND_TIMEOUT = 'send_timeout';
public const OPTION_DISPATCH_MODE = 'dispatch_mode';
public const OPTION_SEND_YIELD = 'send_yield';
public const OPTION_DISPATCH_FUNC = 'dispatch_func';
public const OPTION_DISCARD_TIMEOUT_REQUEST = 'discard_timeout_request';
public const OPTION_ENABLE_UNSAFE_EVENT = 'enable_unsafe_event';
public const OPTION_ENABLE_DELAY_RECEIVE = 'enable_delay_receive';
public const OPTION_ENABLE_REUSE_PORT = 'enable_reuse_port';
public const OPTION_TASK_USE_OBJECT = 'task_use_object';
public const OPTION_TASK_ENABLE_COROUTINE = 'task_enable_coroutine';
public const OPTION_TASK_WORKER_NUM = 'task_worker_num';
public const OPTION_TASK_IPC_MODE = 'task_ipc_mode';
public const OPTION_TASK_TMPDIR = 'task_tmpdir';
public const OPTION_TASK_MAX_REQUEST = 'task_max_request';
public const OPTION_TASK_MAX_REQUEST_GRACE = 'task_max_request_grace';
public const OPTION_MAX_CONNECTION = 'max_connection';
public const OPTION_MAX_CONN = 'max_conn';
public const OPTION_HEARTBEAT_CHECK_INTERVAL = 'heartbeat_check_interval';
public const OPTION_HEARTBEAT_IDLE_TIME = 'heartbeat_idle_time';
public const OPTION_MAX_REQUEST = 'max_request';
public const OPTION_MAX_REQUEST_GRACE = 'max_request_grace';
public const OPTION_RELOAD_ASYNC = 'reload_async';
public const OPTION_OPEN_CPU_AFFINITY = 'open_cpu_affinity';
public const OPTION_CPU_AFFINITY_IGNORE = 'cpu_affinity_ignore';
public const OPTION_ENABLE_STATIC_HANDLER = 'enable_static_handler';
public const OPTION_DOCUMENT_ROOT = 'document_root';
public const OPTION_HTTP_AUTOINDEX = 'http_autoindex';
public const OPTION_HTTP_INDEX_FILES = 'http_index_files';
public const OPTION_STATIC_HANDLER_LOCATIONS = 'static_handler_locations';
public const OPTION_INPUT_BUFFER_SIZE = 'input_buffer_size';
public const OPTION_BUFFER_INPUT_SIZE = 'buffer_input_size';
public const OPTION_OUTPUT_BUFFER_SIZE = 'output_buffer_size';
public const OPTION_BUFFER_OUTPUT_SIZE = 'buffer_output_size';
public const OPTION_MESSAGE_QUEUE_KEY = 'message_queue_key';
public const OPTION_BACKLOG = 'backlog';
public const OPTION_KERNEL_SOCKET_RECV_BUFFER_SIZE = 'kernel_socket_recv_buffer_size';
public const OPTION_KERNEL_SOCKET_SEND_BUFFER_SIZE = 'kernel_socket_send_buffer_size';
public const OPTION_TCP_DEFER_ACCEPT = 'tcp_defer_accept';
public const OPTION_OPEN_TCP_KEEPALIVE = 'open_tcp_keepalive';
public const OPTION_OPEN_HTTP_PROTOCOL = 'open_http_protocol';
public const OPTION_OPEN_WEBSOCKET_PROTOCOL = 'open_websocket_protocol';
public const OPTION_WEBSOCKET_SUBPROTOCOL = 'websocket_subprotocol';
public const OPTION_OPEN_WEBSOCKET_CLOSE_FRAME = 'open_websocket_close_frame';
public const OPTION_OPEN_WEBSOCKET_PING_FRAME = 'open_websocket_ping_frame';
public const OPTION_OPEN_WEBSOCKET_PONG_FRAME = 'open_websocket_pong_frame';
public const OPTION_OPEN_HTTP2_PROTOCOL = 'open_http2_protocol';
public const OPTION_OPEN_REDIS_PROTOCOL = 'open_redis_protocol';
public const OPTION_MAX_IDLE_TIME = 'max_idle_time';
public const OPTION_TCP_KEEPIDLE = 'tcp_keepidle';
public const OPTION_TCP_KEEPINTERVAL = 'tcp_keepinterval';
public const OPTION_TCP_KEEPCOUNT = 'tcp_keepcount';
public const OPTION_TCP_USER_TIMEOUT = 'tcp_user_timeout';
public const OPTION_TCP_FASTOPEN = 'tcp_fastopen';
public const OPTION_PACKAGE_BODY_START = 'package_body_start';
public const OPTION_SSL_CLIENT_CERT_FILE = 'ssl_client_cert_file';
public const OPTION_SSL_PREFER_SERVER_CIPHERS = 'ssl_prefer_server_ciphers';
public const OPTION_SSL_CIPHERS = 'ssl_ciphers';
public const OPTION_SSL_ECDH_CURVE = 'ssl_ecdh_curve';
public const OPTION_SSL_DHPARAM = 'ssl_dhparam';
public const OPTION_OPEN_SSL = 'open_ssl';
public const OPTION_OPEN_FASTCGI_PROTOCOL = 'open_fastcgi_protocol';
/* }}} OPTION */
}
@@ -0,0 +1,64 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\Coroutine;
use Swoole\Coroutine;
use Swoole\Exception;
use Swoole\Timer;
class Barrier
{
private $cid = -1;
private $timer = -1;
private static $cancel_list = [];
public function __destruct()
{
if ($this->timer != -1) {
Timer::clear($this->timer);
if (static::$cancel_list[$this->cid]) {
unset(static::$cancel_list[$this->cid]);
return;
}
}
if ($this->cid != -1) {
Coroutine::resume($this->cid);
}
}
public static function make()
{
return new static();
}
/**
* @throws Exception
*/
public static function wait(Barrier &$barrier, float $timeout = -1)
{
if ($barrier->cid != -1) {
throw new Exception('The barrier is waiting, cannot wait again.');
}
$cid = Coroutine::getCid();
$barrier->cid = $cid;
if ($timeout > 0 && ($timeout_ms = intval($timeout * 1000)) > 0) {
$barrier->timer = Timer::after($timeout_ms, function () use ($cid) {
self::$cancel_list[$cid] = true;
Coroutine::resume($cid);
});
}
$barrier = null;
Coroutine::yield();
}
}
@@ -0,0 +1,177 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\Coroutine\FastCGI;
use InvalidArgumentException;
use Swoole\Coroutine\FastCGI\Client\Exception;
use Swoole\Coroutine\Socket;
use Swoole\FastCGI\FrameParser;
use Swoole\FastCGI\HttpRequest;
use Swoole\FastCGI\HttpResponse;
use Swoole\FastCGI\Record\EndRequest;
use Swoole\FastCGI\Request;
use Swoole\FastCGI\Response;
class Client
{
/** @var int */
protected $af;
/** @var string */
protected $host;
/** @var int */
protected $port;
/** @var bool */
protected $ssl;
/** @var Socket */
protected $socket;
public function __construct(string $host, int $port = 0, bool $ssl = false)
{
if (stripos($host, 'unix:/') === 0) {
$this->af = AF_UNIX;
$host = '/' . ltrim(substr($host, strlen('unix:/')), '/');
$port = 0;
} elseif (strpos($host, ':') !== false) {
$this->af = AF_INET6;
} else {
$this->af = AF_INET;
}
$this->host = $host;
$this->port = $port;
$this->ssl = $ssl;
}
/**
* @throws Exception
* @return HttpResponse|Response
*/
public function execute(Request $request, float $timeout = -1): Response
{
if (!$this->socket) {
$this->socket = $socket = new Socket($this->af, SOCK_STREAM, IPPROTO_IP);
$socket->setProtocol([
'open_ssl' => $this->ssl,
'open_fastcgi_protocol' => true,
]);
if (!$socket->connect($this->host, $this->port, $timeout)) {
$this->ioException();
}
} else {
$socket = $this->socket;
}
$sendData = (string) $request;
if ($socket->sendAll($sendData) !== strlen($sendData)) {
$this->ioException();
}
$records = [];
while (true) {
if (SWOOLE_VERSION_ID < 40500) {
$recvData = '';
while (true) {
$tmp = $socket->recv(8192, $timeout);
if (!$tmp) {
if ($tmp === '') {
$this->ioException(SOCKET_ECONNRESET);
}
$this->ioException();
}
$recvData .= $tmp;
if (FrameParser::hasFrame($recvData)) {
break;
}
}
} else {
$recvData = $socket->recvPacket($timeout);
if (!$recvData) {
if ($recvData === '') {
$this->ioException(SOCKET_ECONNRESET);
}
$this->ioException();
}
if (!FrameParser::hasFrame($recvData)) {
$this->ioException(SOCKET_EPROTO);
}
}
do {
$records[] = $record = FrameParser::parseFrame($recvData);
} while (strlen($recvData) !== 0);
if ($record instanceof EndRequest) {
if (!$request->getKeepConn()) {
$this->socket->close();
$this->socket = null;
}
switch (true) {
case $request instanceof HttpRequest:
return new HttpResponse($records);
default:
return new Response($records);
}
}
}
/* never here */
exit(1);
}
public static function parseUrl(string $url): array
{
$url = parse_url($url);
$host = $url['host'] ?? '';
$port = $url['port'] ?? 0;
if (empty($host)) {
$host = $url['path'] ?? '';
if (empty($host)) {
throw new InvalidArgumentException('Invalid url');
}
$host = "unix:/{$host}";
}
return [$host, $port];
}
public static function call(string $url, string $path, $data = '', float $timeout = -1): string
{
$client = new Client(...static::parseUrl($url));
$pathInfo = parse_url($path);
$path = $pathInfo['path'] ?? '';
$root = dirname($path);
$scriptName = '/' . basename($path);
$documentUri = $scriptName;
$query = $pathInfo['query'] ?? '';
$requestUri = $query ? "{$documentUri}?{$query}" : $documentUri;
$request = new HttpRequest();
$request->withDocumentRoot($root)
->withScriptFilename($path)
->withScriptName($documentUri)
->withDocumentUri($documentUri)
->withRequestUri($requestUri)
->withQueryString($query)
->withBody($data)
->withMethod($request->getContentLength() === 0 ? 'GET' : 'POST');
$response = $client->execute($request, $timeout);
return $response->getBody();
}
protected function ioException(?int $errno = null): void
{
$socket = $this->socket;
if ($errno !== null) {
$socket->errCode = $errno;
$socket->errMsg = swoole_strerror($errno);
}
$socket->close();
$this->socket = null;
throw new Exception($socket->errMsg, $socket->errCode);
}
}
@@ -0,0 +1,16 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\Coroutine\FastCGI\Client;
class Exception extends \Swoole\Exception
{
}
@@ -0,0 +1,205 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\Coroutine\FastCGI;
use InvalidArgumentException;
use Swoole\FastCGI\HttpRequest;
use Swoole\FastCGI\HttpResponse;
use Swoole\Http;
class Proxy
{
/* @var string */
protected $host;
/* @var int */
protected $port;
/* @var float */
protected $timeout = -1;
/* @var string */
protected $documentRoot;
/* @var bool */
protected $https = false;
/* @var string */
protected $index = 'index.php';
/* @var array */
protected $params = [];
/* @var null|callable */
protected $staticFileFilter;
public function __construct(string $url, string $documentRoot = '/')
{
[$this->host, $this->port] = Client::parseUrl($url);
$this->documentRoot = $documentRoot;
$this->staticFileFilter = [$this, 'staticFileFiltrate'];
}
public function withTimeout(float $timeout): self
{
$this->timeout = $timeout;
return $this;
}
public function withHttps(bool $https): self
{
$this->https = $https;
return $this;
}
public function withIndex(string $index): self
{
$this->index = $index;
return $this;
}
public function getParam(string $name): ?string
{
return $this->params[$name] ?? null;
}
public function withParam(string $name, string $value): self
{
$this->params[$name] = $value;
return $this;
}
public function withoutParam(string $name): self
{
unset($this->params[$name]);
return $this;
}
public function getParams(): array
{
return $this->params;
}
public function withParams(array $params): self
{
$this->params = $params;
return $this;
}
public function withAddedParams(array $params): self
{
$this->params = $params + $this->params;
return $this;
}
public function withStaticFileFilter(?callable $filter): self
{
$this->staticFileFilter = $filter;
return $this;
}
public function translateRequest($userRequest): HttpRequest
{
$request = new HttpRequest();
if ($userRequest instanceof \Swoole\Http\Request) {
$server = $userRequest->server;
$headers = $userRequest->header;
$pathInfo = $userRequest->server['path_info'];
$pathInfo = '/' . (ltrim($pathInfo, '/'));
if (strlen($this->index) !== 0) {
$extension = pathinfo($pathInfo, PATHINFO_EXTENSION);
if (empty($extension)) {
$pathInfo = rtrim($pathInfo, '/') . '/' . $this->index;
}
}
$requestUri = $scriptName = $documentUri = $server['request_uri'];
$queryString = $server['query_string'] ?? '';
if (strlen($queryString) !== 0) {
$requestUri .= "?{$server['query_string']}";
}
$request
->withDocumentRoot($this->documentRoot)
->withScriptFilename($this->documentRoot . $pathInfo)
->withScriptName($scriptName)
->withDocumentUri($documentUri)
->withServerProtocol($server['server_protocol'])
->withServerAddr('127.0.0.1')
->withServerPort($server['server_port'])
->withRemoteAddr($server['remote_addr'])
->withRemotePort($server['remote_port'])
->withMethod($server['request_method'])
->withRequestUri($requestUri)
->withQueryString($queryString)
->withContentType($headers['content-type'] ?? '')
->withContentLength((int) ($headers['content-length'] ?? 0))
->withHeaders($headers)
->withBody($userRequest->rawContent())
->withAddedParams($this->params);
if ($this->https) {
$request->withParam('HTTPS', '1');
}
} else {
throw new InvalidArgumentException('Not supported on ' . get_class($userRequest));
}
return $request;
}
public function translateResponse(HttpResponse $response, $userResponse): void
{
if ($userResponse instanceof \Swoole\Http\Response) {
$userResponse->status($response->getStatusCode(), $response->getReasonPhrase());
$userResponse->header = $response->getHeaders();
$userResponse->cookie = $response->getSetCookieHeaderLines();
$userResponse->end($response->getBody());
} else {
throw new InvalidArgumentException('Not supported on ' . get_class($userResponse));
}
}
public function pass($userRequest, $userResponse): void
{
if (!($userRequest instanceof HttpRequest)) {
$request = $this->translateRequest($userRequest);
} else {
$request = $userRequest;
}
unset($userRequest);
if ($this->staticFileFilter) {
$filter = $this->staticFileFilter;
if ($filter($request, $userResponse)) {
return;
}
}
$client = new Client($this->host, $this->port);
$response = $client->execute($request, $this->timeout);
$this->translateResponse($response, $userResponse);
}
/* @return bool ['hit' => true, 'miss' => false] */
public function staticFileFiltrate(HttpRequest $request, $userResponse): bool
{
if ($userResponse instanceof \Swoole\Http\Response) {
$extension = pathinfo($request->getScriptFilename(), PATHINFO_EXTENSION);
if ($extension !== 'php') {
$realPath = realpath($request->getScriptFilename());
if (!$realPath || strpos($realPath, $this->documentRoot) !== 0 || !is_file($realPath)) {
$userResponse->status(Http\Status::NOT_FOUND);
} else {
$userResponse->sendfile($realPath);
}
return true;
}
return false;
}
throw new InvalidArgumentException('Not supported on ' . get_class($userResponse));
}
}
@@ -0,0 +1,153 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\Coroutine;
use Swoole\Coroutine;
use Swoole\Coroutine\Server\Connection;
use Swoole\Exception;
/* compatibility constant */
define('SWOOLE_COROUTINE_SOCKET_HAVE_SSL_HANDSHAKE', method_exists(Socket::class, 'sslHandshake'));
class Server
{
/** @var string */
public $host = '';
/** @var int */
public $port = 0;
/** @var int */
public $type = AF_INET;
/** @var int */
public $fd = -1;
/** @var int */
public $errCode = 0;
/** @var array */
public $setting = [];
/** @var bool */
protected $running = false;
/** @var null|callable */
protected $fn;
/** @var Socket */
protected $socket;
/**
* Server constructor.
* @throws Exception
*/
public function __construct(string $host, int $port = 0, bool $ssl = false, bool $reuse_port = false)
{
$_host = swoole_string($host);
if ($_host->contains('::')) {
$this->type = AF_INET6;
} elseif ($_host->startsWith('unix:/')) {
$host = $_host->substr(5)->__toString();
$this->type = AF_UNIX;
} else {
$this->type = AF_INET;
}
$this->host = $host;
$socket = new Socket($this->type, SOCK_STREAM, 0);
if ($reuse_port and defined('SO_REUSEPORT')) {
$socket->setOption(SOL_SOCKET, SO_REUSEPORT, true);
}
if (!$socket->bind($this->host, $port)) {
throw new Exception("bind({$this->host}:{$port}) failed", $socket->errCode);
}
if (!$socket->listen()) {
throw new Exception('listen() failed', $socket->errCode);
}
$this->port = $socket->getsockname()['port'] ?? 0;
$this->fd = $socket->fd;
$this->socket = $socket;
$this->setting['open_ssl'] = $ssl;
}
public function set(array $setting): void
{
$this->setting = array_merge($this->setting, $setting);
}
public function handle(callable $fn): void
{
$this->fn = $fn;
}
public function shutdown(): bool
{
$this->running = false;
return $this->socket->cancel();
}
public function start(): bool
{
$this->running = true;
if ($this->fn === null) {
$this->errCode = SOCKET_EINVAL;
return false;
}
$socket = $this->socket;
if (!$socket->setProtocol($this->setting)) {
$this->errCode = SOCKET_EINVAL;
return false;
}
while ($this->running) {
/** @var Socket $conn */
$conn = null;
$conn = $socket->accept();
if ($conn) {
$conn->setProtocol($this->setting);
if (SWOOLE_COROUTINE_SOCKET_HAVE_SSL_HANDSHAKE && $this->setting['open_ssl'] ?? false) {
$fn = static function ($fn, $connection) {
/* @var $connection Connection */
if (!$connection->exportSocket()->sslHandshake()) {
return;
}
$fn($connection);
};
$arguments = [$this->fn, new Connection($conn)];
} else {
$fn = $this->fn;
$arguments = [new Connection($conn)];
}
if (Coroutine::create($fn, ...$arguments) < 0) {
goto _wait;
}
} else {
if ($socket->errCode == SOCKET_EMFILE or $socket->errCode == SOCKET_ENFILE) {
_wait:
Coroutine::sleep(1);
continue;
}
if ($socket->errCode == SOCKET_ETIMEDOUT) {
continue;
}
if ($socket->errCode == SOCKET_ECANCELED) {
break;
}
trigger_error("accept failed, Error: {$socket->errMsg}[{$socket->errCode}]", E_USER_WARNING);
break;
}
}
return true;
}
}
@@ -0,0 +1,44 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\Coroutine\Server;
use Swoole\Coroutine\Socket;
class Connection
{
protected $socket;
public function __construct(Socket $conn)
{
$this->socket = $conn;
}
public function recv(float $timeout = 0)
{
return $this->socket->recvPacket($timeout);
}
public function send(string $data)
{
return $this->socket->sendAll($data);
}
public function close(): bool
{
return $this->socket->close();
}
public function exportSocket(): Socket
{
return $this->socket;
}
}
@@ -0,0 +1,70 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\Coroutine;
use BadMethodCallException;
use InvalidArgumentException;
class WaitGroup
{
protected $chan;
protected $count = 0;
protected $waiting = false;
public function __construct(int $delta = 0)
{
$this->chan = new Channel(1);
if ($delta > 0) {
$this->add($delta);
}
}
public function add(int $delta = 1): void
{
if ($this->waiting) {
throw new BadMethodCallException('WaitGroup misuse: add called concurrently with wait');
}
$count = $this->count + $delta;
if ($count < 0) {
throw new InvalidArgumentException('WaitGroup misuse: negative counter');
}
$this->count = $count;
}
public function done(): void
{
$count = $this->count - 1;
if ($count < 0) {
throw new BadMethodCallException('WaitGroup misuse: negative counter');
}
$this->count = $count;
if ($count === 0 && $this->waiting) {
$this->chan->push(true);
}
}
public function wait(float $timeout = -1): bool
{
if ($this->waiting) {
throw new BadMethodCallException('WaitGroup misuse: reused before previous wait has returned');
}
if ($this->count > 0) {
$this->waiting = true;
$done = $this->chan->pop($timeout);
$this->waiting = false;
return $done;
}
return true;
}
}
@@ -0,0 +1,55 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\Coroutine;
use Swoole\Coroutine;
function batch(array $tasks, float $timeout = -1): array
{
$wg = new WaitGroup(count($tasks));
foreach ($tasks as $id => $task) {
Coroutine::create(function () use ($wg, &$tasks, $id, $task) {
$tasks[$id] = null;
$tasks[$id] = $task();
$wg->done();
});
}
$wg->wait($timeout);
return $tasks;
}
function parallel(int $n, callable $fn): void
{
$count = $n;
$wg = new WaitGroup($n);
while ($count--) {
Coroutine::create(function () use ($fn, $wg) {
$fn();
$wg->done();
});
}
$wg->wait();
}
function map(array $list, callable $fn, float $timeout = -1): array
{
$wg = new WaitGroup(count($list));
foreach ($list as $id => $elem) {
Coroutine::create(function () use ($wg, &$list, $id, $elem, $fn): void {
$list[$id] = null;
$list[$id] = $fn($elem);
$wg->done();
});
}
$wg->wait($timeout);
return $list;
}
@@ -0,0 +1,18 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\Curl;
use Swoole;
class Exception extends Swoole\Exception
{
}
@@ -0,0 +1,869 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
/* @noinspection PhpComposerExtensionStubsInspection, PhpDuplicateSwitchCaseBodyInspection, PhpInconsistentReturnPointsInspection */
declare(strict_types=1);
namespace Swoole\Curl;
use CURLFile;
use ReflectionClass;
use Swoole;
use Swoole\Constant;
use Swoole\Coroutine\Http\Client;
use Swoole\Curl\Exception as CurlException;
use Swoole\Http\Status;
final class Handler
{
/**
* @var Client
*/
private $client;
private $info = [
'url' => '',
'content_type' => '',
'http_code' => 0,
'header_size' => 0,
'request_size' => 0,
'filetime' => -1,
'ssl_verify_result' => 0,
'redirect_count' => 0,
'total_time' => 5.3E-5,
'namelookup_time' => 0.0,
'connect_time' => 0.0,
'pretransfer_time' => 0.0,
'size_upload' => 0.0,
'size_download' => 0.0,
'speed_download' => 0.0,
'speed_upload' => 0.0,
'download_content_length' => -1.0,
'upload_content_length' => -1.0,
'starttransfer_time' => 0.0,
'redirect_time' => 0.0,
'redirect_url' => '',
'primary_ip' => '',
'certinfo' => [],
'primary_port' => 0,
'local_ip' => '',
'local_port' => 0,
'http_version' => 0,
'protocol' => 0,
'ssl_verifyresult' => 0,
'scheme' => '',
];
private $withHeaderOut = false;
private $withFileTime = false;
private $urlInfo;
private $postData;
private $infile;
private $infileSize = PHP_INT_MAX;
private $outputStream;
private $proxyType;
private $proxy;
private $proxyPort = 1080;
private $proxyUsername;
private $proxyPassword;
private $clientOptions = [];
private $followLocation = false;
private $autoReferer = false;
private $maxRedirects;
private $withHeader = false;
private $nobody = false;
/** @var callable */
private $headerFunction;
/** @var callable */
private $readFunction;
/** @var callable */
private $writeFunction;
/** @var callable */
private $progressFunction;
private $returnTransfer = false;
private $method = '';
private $headers = [];
private $transfer;
private $errCode = 0;
private $errMsg = '';
private $failOnError = false;
private $closed = false;
public function __construct(string $url = '')
{
if ($url) {
$this->setUrl($url);
}
}
public function __toString()
{
if (PHP_VERSION_ID < 70200) {
$id = spl_object_hash($this);
} else {
$id = spl_object_id($this);
}
return "Object({$id}) of type (curl)";
}
/* ====== Public APIs ====== */
public function isAvailable(): bool
{
if ($this->closed) {
trigger_error('supplied resource is not a valid cURL handle resource', E_USER_WARNING);
return false;
}
return true;
}
public function setOpt(int $opt, $value): bool
{
return $this->isAvailable() and $this->setOption($opt, $value);
}
public function exec()
{
if (!$this->isAvailable()) {
return false;
}
return $this->execute();
}
public function getInfo()
{
return $this->isAvailable() ? $this->info : false;
}
public function errno()
{
return $this->isAvailable() ? $this->errCode : false;
}
public function error()
{
return $this->isAvailable() ? $this->errMsg : false;
}
public function reset()
{
if (!$this->isAvailable()) {
return false;
}
foreach ((new ReflectionClass(static::class))->getDefaultProperties() as $name => $value) {
$this->{$name} = $value;
}
}
public function getContent()
{
if (!$this->isAvailable()) {
return false;
}
return $this->transfer;
}
public function close()
{
if (!$this->isAvailable()) {
return false;
}
foreach ($this as &$property) {
$property = null;
}
$this->closed = true;
}
private function create(?array $urlInfo = null): void
{
if ($urlInfo === null) {
$urlInfo = $this->urlInfo;
}
$this->client = new Client($urlInfo['host'], $urlInfo['port'], $urlInfo['scheme'] === 'https');
}
private function getUrl(): string
{
if (empty($this->urlInfo['path'])) {
$url = '/';
} else {
$url = $this->urlInfo['path'];
}
if (!empty($this->urlInfo['query'])) {
$url .= '?' . $this->urlInfo['query'];
}
if (!empty($this->urlInfo['fragment'])) {
$url .= '#' . $this->urlInfo['fragment'];
}
return $url;
}
private function setUrl(string $url, bool $setInfo = true): bool
{
if (strlen($url) === 0) {
$this->setError(CURLE_URL_MALFORMAT, 'No URL set!');
return false;
}
if (strpos($url, '://') === false) {
$url = 'http://' . $url;
}
if ($setInfo) {
$urlInfo = parse_url($url);
if (!is_array($urlInfo)) {
$this->setError(CURLE_URL_MALFORMAT, "URL[{$url}] using bad/illegal format");
return false;
}
if (!$this->setUrlInfo($urlInfo)) {
return false;
}
}
$this->info['url'] = $url;
return true;
}
private function setUrlInfo(array $urlInfo): bool
{
if (empty($urlInfo['scheme'])) {
$urlInfo['scheme'] = 'http';
}
$scheme = $urlInfo['scheme'];
if ($scheme !== 'http' and $scheme !== 'https') {
$this->setError(CURLE_UNSUPPORTED_PROTOCOL, "Protocol \"{$scheme}\" not supported or disabled in libcurl");
return false;
}
$host = $urlInfo['host'];
if ($this->info['primary_port'] !== 0) {
/* keep same with cURL, primary_port has the highest priority */
$urlInfo['port'] = $this->info['primary_port'];
} elseif (empty($urlInfo['port'])) {
$urlInfo['port'] = $scheme === 'https' ? 443 : 80;
} else {
$urlInfo['port'] = intval($urlInfo['port']);
}
$port = $urlInfo['port'];
if ($this->client) {
$oldUrlInfo = $this->urlInfo;
if (
$host !== $oldUrlInfo['host'] or
$port !== $oldUrlInfo['port'] or
$scheme !== $oldUrlInfo['scheme']
) {
/* target changed */
$this->create($urlInfo);
}
}
$this->urlInfo = $urlInfo;
return true;
}
private function setPort(int $port): void
{
$this->info['primary_port'] = $port;
if ($this->urlInfo['port'] !== $port) {
$this->urlInfo['port'] = $port;
if ($this->client) {
/* target changed */
$this->create();
}
}
}
private function setError($code, $msg = ''): void
{
$this->errCode = $code;
$this->errMsg = $msg ? $msg : curl_strerror($code);
}
/**
* @param mixed $value
* @throws Swoole\Curl\Exception
*/
private function setOption(int $opt, $value): bool
{
switch ($opt) {
// case CURLOPT_STDERR:
// case CURLOPT_WRITEHEADER:
case CURLOPT_FILE:
case CURLOPT_INFILE:
if (!is_resource($value)) {
trigger_error(E_USER_WARNING, 'swoole_curl_setopt(): supplied argument is not a valid File-Handle resource');
return false;
}
break;
}
switch ($opt) {
/*
* Basic
*/
case CURLOPT_URL:
return $this->setUrl((string) $value);
case CURLOPT_PORT:
$this->setPort((int) $value);
break;
case CURLOPT_FORBID_REUSE:
$this->clientOptions[Constant::OPTION_KEEP_ALIVE] = !$value;
break;
case CURLOPT_RETURNTRANSFER:
$this->returnTransfer = $value;
$this->transfer = '';
break;
case CURLOPT_ENCODING:
if (empty($value)) {
if (defined('SWOOLE_HAVE_ZLIB')) {
$value = 'gzip, deflate';
}
if (defined('SWOOLE_HAVE_BROTLI')) {
if (!empty($value)) {
$value = 'br, ' . $value;
} else {
$value = 'br';
}
}
if (empty($value)) {
break;
}
}
$this->headers['Accept-Encoding'] = $value;
break;
case CURLOPT_PROXYTYPE:
if ($value !== CURLPROXY_HTTP and $value !== CURLPROXY_SOCKS5) {
throw new Swoole\Curl\Exception(
'swoole_curl_setopt(): Only support following CURLOPT_PROXYTYPE values: CURLPROXY_HTTP, CURLPROXY_SOCKS5'
);
}
$this->proxyType = $value;
break;
case CURLOPT_PROXY:
$this->proxy = $value;
break;
case CURLOPT_PROXYPORT:
$this->proxyPort = $value;
break;
case CURLOPT_PROXYUSERNAME:
$this->proxyUsername = $value;
break;
case CURLOPT_PROXYPASSWORD:
$this->proxyPassword = $value;
break;
case CURLOPT_PROXYUSERPWD:
$usernamePassword = explode(':', $value);
$this->proxyUsername = urldecode($usernamePassword[0]);
$this->proxyPassword = urldecode($usernamePassword[1] ?? null);
break;
case CURLOPT_PROXYAUTH:
/* ignored temporarily */
break;
case CURLOPT_NOBODY:
$this->nobody = boolval($value);
$this->method = 'HEAD';
break;
case CURLOPT_IPRESOLVE:
if ($value !== CURL_IPRESOLVE_WHATEVER and $value !== CURL_IPRESOLVE_V4) {
throw new Swoole\Curl\Exception(
'swoole_curl_setopt(): Only support following CURLOPT_IPRESOLVE values: CURL_IPRESOLVE_WHATEVER, CURL_IPRESOLVE_V4'
);
}
break;
/*
* Ignore options
*/
case CURLOPT_VERBOSE:
// trigger_error(E_USER_WARNING, 'swoole_curl_setopt(): CURLOPT_VERBOSE is not supported');
case CURLOPT_SSLVERSION:
case CURLOPT_NOSIGNAL:
case CURLOPT_FRESH_CONNECT:
/*
* From PHP 5.1.3, this option has no effect: the raw output will always be returned when CURLOPT_RETURNTRANSFER is used.
*/
case CURLOPT_BINARYTRANSFER: /* TODO */
case CURLOPT_DNS_USE_GLOBAL_CACHE:
case CURLOPT_DNS_CACHE_TIMEOUT:
case CURLOPT_STDERR:
case CURLOPT_WRITEHEADER:
case CURLOPT_BUFFERSIZE:
case CURLOPT_SSLCERTTYPE:
case CURLOPT_SSLKEYTYPE:
break;
/*
* SSL
*/
case CURLOPT_SSL_VERIFYHOST:
break;
case CURLOPT_SSL_VERIFYPEER:
$this->clientOptions[Constant::OPTION_SSL_VERIFY_PEER] = $value;
break;
case CURLOPT_SSLCERT:
$this->clientOptions[Constant::OPTION_SSL_CERT_FILE] = $value;
break;
case CURLOPT_SSLKEY:
$this->clientOptions[Constant::OPTION_SSL_KEY_FILE] = $value;
break;
case CURLOPT_CAINFO:
$this->clientOptions[Constant::OPTION_SSL_CAFILE] = $value;
break;
case CURLOPT_CAPATH:
$this->clientOptions[Constant::OPTION_SSL_CAPATH] = $value;
break;
/*
* Http POST
*/
case CURLOPT_POST:
$this->method = 'POST';
break;
case CURLOPT_POSTFIELDS:
$this->postData = $value;
if (!$this->method) {
$this->method = 'POST';
}
break;
/*
* Upload
*/
case CURLOPT_SAFE_UPLOAD:
if (!$value) {
trigger_error('swoole_curl_setopt(): Disabling safe uploads is no longer supported', E_USER_WARNING);
return false;
}
break;
/*
* Http Header
*/
case CURLOPT_HTTPHEADER:
if (!is_array($value) and !is_iterable($value)) {
trigger_error('swoole_curl_setopt(): You must pass either an object or an array with the CURLOPT_HTTPHEADER argument', E_USER_WARNING);
return false;
}
foreach ($value as $header) {
$header = explode(':', $header, 2);
$headerName = $header[0];
$headerValue = trim($header[1] ?? '');
if (strlen($headerValue) === 0) {
continue;
}
$this->headers[$headerName] = $headerValue;
}
break;
case CURLOPT_REFERER:
$this->headers['Referer'] = $value;
break;
case CURLINFO_HEADER_OUT:
$this->withHeaderOut = boolval($value);
break;
case CURLOPT_FILETIME:
$this->withFileTime = boolval($value);
break;
case CURLOPT_USERAGENT:
$this->headers['User-Agent'] = $value;
break;
case CURLOPT_CUSTOMREQUEST:
$this->method = (string) $value;
break;
case CURLOPT_PROTOCOLS:
if (($value & ~(CURLPROTO_HTTP | CURLPROTO_HTTPS)) != 0) {
throw new CurlException("swoole_curl_setopt(): CURLOPT_PROTOCOLS[{$value}] is not supported");
}
break;
case CURLOPT_REDIR_PROTOCOLS:
if (($value & ~(CURLPROTO_HTTP | CURLPROTO_HTTPS)) != 0) {
throw new CurlException("swoole_curl_setopt(): CURLOPT_REDIR_PROTOCOLS[{$value}] is not supported");
}
break;
case CURLOPT_HTTP_VERSION:
if ($value != CURL_HTTP_VERSION_1_1) {
trigger_error("swoole_curl_setopt(): CURLOPT_HTTP_VERSION[{$value}] is not supported", E_USER_WARNING);
return false;
}
break;
case CURLOPT_FAILONERROR:
$this->failOnError = $value;
break;
/*
* Http Cookie
*/
case CURLOPT_COOKIE:
$this->headers['Cookie'] = $value;
break;
case CURLOPT_CONNECTTIMEOUT:
$this->clientOptions[Constant::OPTION_CONNECT_TIMEOUT] = $value;
break;
case CURLOPT_CONNECTTIMEOUT_MS:
$this->clientOptions[Constant::OPTION_CONNECT_TIMEOUT] = $value / 1000;
break;
case CURLOPT_TIMEOUT:
$this->clientOptions[Constant::OPTION_TIMEOUT] = $value;
break;
case CURLOPT_TIMEOUT_MS:
$this->clientOptions[Constant::OPTION_TIMEOUT] = $value / 1000;
break;
case CURLOPT_FILE:
$this->outputStream = $value;
break;
case CURLOPT_HEADER:
$this->withHeader = $value;
break;
case CURLOPT_HEADERFUNCTION:
$this->headerFunction = $value;
break;
case CURLOPT_READFUNCTION:
$this->readFunction = $value;
break;
case CURLOPT_WRITEFUNCTION:
$this->writeFunction = $value;
break;
case CURLOPT_PROGRESSFUNCTION:
$this->progressFunction = $value;
break;
case CURLOPT_HTTPAUTH:
if (!($value & CURLAUTH_BASIC)) {
trigger_error("swoole_curl_setopt(): CURLOPT_HTTPAUTH[{$value}] is not supported", E_USER_WARNING);
return false;
}
break;
case CURLOPT_USERPWD:
$this->headers['Authorization'] = 'Basic ' . base64_encode($value);
break;
case CURLOPT_FOLLOWLOCATION:
$this->followLocation = $value;
break;
case CURLOPT_AUTOREFERER:
$this->autoReferer = $value;
break;
case CURLOPT_MAXREDIRS:
$this->maxRedirects = $value;
break;
case CURLOPT_PUT:
case CURLOPT_UPLOAD:
/* after libcurl 7.12, CURLOPT_PUT is replaced by CURLOPT_UPLOAD */
$this->method = 'PUT';
break;
case CURLOPT_INFILE:
$this->infile = $value;
break;
case CURLOPT_INFILESIZE:
$this->infileSize = $value;
break;
case CURLOPT_HTTPGET:
/* Since GET is the default, this is only necessary if the request method has been changed. */
$this->method = 'GET';
break;
default:
throw new Swoole\Curl\Exception("swoole_curl_setopt(): option[{$opt}] is not supported");
}
return true;
}
private function execute()
{
$this->info['redirect_count'] = $this->info['starttransfer_time'] = 0;
$this->info['redirect_url'] = '';
$timeBegin = microtime(true);
/*
* Socket
*/
if (!$this->urlInfo) {
$this->setError(CURLE_URL_MALFORMAT, 'No URL set or URL using bad/illegal format');
return false;
}
if (!$this->client) {
$this->create();
}
do {
$client = $this->client;
/*
* Http Proxy
*/
if ($this->proxy) {
$proxy = explode(':', $this->proxy);
$proxyPort = $proxy[1] ?? $this->proxyPort;
$proxy = $proxy[0];
if (!filter_var($proxy, FILTER_VALIDATE_IP)) {
$ip = Swoole\Coroutine::gethostbyname($proxy, AF_INET, $this->clientOptions['connect_timeout'] ?? -1);
if (!$ip) {
$this->setError(CURLE_COULDNT_RESOLVE_PROXY, 'Could not resolve proxy: ' . $proxy);
return false;
}
$this->proxy = $proxy = $ip;
}
switch ($this->proxyType) {
case CURLPROXY_HTTP:
$proxyOptions = [
'http_proxy_host' => $proxy,
'http_proxy_port' => $proxyPort,
'http_proxy_username' => $this->proxyUsername,
'http_proxy_password' => $this->proxyPassword,
];
break;
case CURLPROXY_SOCKS5:
$proxyOptions = [
'socks5_host' => $proxy,
'socks5_port' => $proxyPort,
'socks5_username' => $this->proxyUsername,
'socks5_password' => $this->proxyPassword,
];
break;
default:
throw new CurlException("Unexpected proxy type [{$this->proxyType}]");
}
}
/*
* Client Options
*/
$client->set(
$this->clientOptions +
($proxyOptions ?? [])
);
/*
* Method
*/
if ($this->method) {
$client->setMethod($this->method);
}
/*
* Data
*/
if ($this->infile) {
// Infile
// Notice: we make its priority higher than postData but raw cURL will send both of them
$data = '';
while (true) {
$nLength = $this->infileSize - strlen($data);
if ($nLength === 0) {
break;
}
if (feof($this->infile)) {
break;
}
$data .= fread($this->infile, $nLength);
}
$client->setData($data);
// Notice: although we reset it, raw cURL never do this
$this->infile = null;
$this->infileSize = PHP_INT_MAX;
} else {
// POST data
if ($this->postData) {
if (is_string($this->postData)) {
if (empty($this->headers['Content-Type'])) {
$this->headers['Content-Type'] = 'application/x-www-form-urlencoded';
}
} elseif (is_array($this->postData)) {
foreach ($this->postData as $k => $v) {
if ($v instanceof CURLFile) {
$client->addFile($v->getFilename(), $k, $v->getMimeType() ?: 'application/octet-stream', $v->getPostFilename());
unset($this->postData[$k]);
}
}
}
}
$client->setData($this->postData);
}
/*
* Headers
*/
// Notice: setHeaders must be placed last, because headers may be changed by other parts
// As much as possible to ensure that Host is the first header.
// See: http://tools.ietf.org/html/rfc7230#section-5.4
foreach ($this->headers as $headerName => $headerValue) {
if ($headerValue === '') {
// remove empty headers (keep same with raw cURL)
unset($this->headers[$headerName]);
}
}
$client->setHeaders($this->headers);
/**
* Execute.
*/
$executeResult = $client->execute($this->getUrl());
if (!$executeResult) {
$errCode = $client->errCode;
if ($errCode == SWOOLE_ERROR_DNSLOOKUP_RESOLVE_FAILED or $errCode == SWOOLE_ERROR_DNSLOOKUP_RESOLVE_TIMEOUT) {
$this->setError(CURLE_COULDNT_RESOLVE_HOST, 'Could not resolve host: ' . $client->host);
} else {
$this->setError($errCode, $client->errMsg);
}
$this->info['total_time'] = microtime(true) - $timeBegin;
return false;
}
if ($client->statusCode >= 300 and $client->statusCode < 400 and isset($client->headers['location'])) {
$redirectParsedUrl = $this->getRedirectUrl($client->headers['location']);
$redirectUrl = static::unparseUrl($redirectParsedUrl);
if ($this->followLocation and ($this->maxRedirects === null or $this->info['redirect_count'] < $this->maxRedirects)) {
if ($this->info['redirect_count'] === 0) {
$this->info['starttransfer_time'] = microtime(true) - $timeBegin;
$redirectBeginTime = microtime(true);
}
// force GET
if (in_array($client->statusCode, [Status::MOVED_PERMANENTLY, Status::FOUND, Status::SEE_OTHER])) {
$this->method = 'GET';
}
if ($this->autoReferer) {
$this->headers['Referer'] = $this->info['url'];
}
$this->setUrl($redirectUrl, false);
$this->setUrlInfo($redirectParsedUrl);
$this->info['redirect_count']++;
} else {
$this->info['redirect_url'] = $redirectUrl;
break;
}
} elseif ($this->failOnError && $client->statusCode >= 400) {
$this->setError(CURLE_HTTP_RETURNED_ERROR, "The requested URL returned error: {$client->statusCode} " . Status::getReasonPhrase($client->statusCode));
return false;
} else {
break;
}
} while (true);
$this->info['total_time'] = microtime(true) - $timeBegin;
$this->info['http_code'] = $client->statusCode;
$this->info['content_type'] = $client->headers['content-type'] ?? '';
$this->info['size_download'] = $this->info['download_content_length'] = strlen($client->body);
$this->info['speed_download'] = 1 / $this->info['total_time'] * $this->info['size_download'];
if (isset($redirectBeginTime)) {
$this->info['redirect_time'] = microtime(true) - $redirectBeginTime;
}
$headerContent = '';
if ($client->headers) {
$cb = $this->headerFunction;
if ($client->statusCode > 0) {
$row = "HTTP/1.1 {$client->statusCode} " . Status::getReasonPhrase($client->statusCode) . "\r\n";
if ($cb) {
$cb($this, $row);
}
$headerContent .= $row;
}
foreach ($client->headers as $k => $v) {
$row = "{$k}: {$v}\r\n";
if ($cb) {
$cb($this, $row);
}
$headerContent .= $row;
}
$headerContent .= "\r\n";
$this->info['header_size'] = strlen($headerContent);
if ($cb) {
$cb($this, '');
}
} else {
$this->info['header_size'] = 0;
}
if ($client->body and $this->readFunction) {
$cb = $this->readFunction;
$cb($this, $this->outputStream, strlen($client->body));
}
if ($this->withHeader) {
$transfer = $headerContent . $client->body;
} else {
$transfer = $client->body;
}
if ($this->withHeaderOut) {
$headerOutContent = $client->getHeaderOut();
$this->info['request_header'] = $headerOutContent ? $headerOutContent . "\r\n\r\n" : '';
}
if ($this->withFileTime) {
if (isset($client->headers['last-modified'])) {
$this->info['filetime'] = strtotime($client->headers['last-modified']);
} else {
$this->info['filetime'] = -1;
}
}
if ($this->returnTransfer) {
return $this->transfer = $transfer;
}
if ($this->outputStream) {
return fwrite($this->outputStream, $transfer) === strlen($transfer);
}
echo $transfer;
return true;
}
/* ====== Redirect helper ====== */
private static function unparseUrl(array $parsedUrl): string
{
$scheme = ($parsedUrl['scheme'] ?? 'http') . '://';
$host = $parsedUrl['host'] ?? '';
$port = isset($parsedUrl['port']) ? ':' . $parsedUrl['port'] : '';
$user = $parsedUrl['user'] ?? '';
$pass = isset($parsedUrl['pass']) ? ':' . $parsedUrl['pass'] : '';
$pass = ($user or $pass) ? "{$pass}@" : '';
$path = $parsedUrl['path'] ?? '';
$query = (isset($parsedUrl['query']) and $parsedUrl['query'] !== '') ? '?' . $parsedUrl['query'] : '';
$fragment = isset($parsedUrl['fragment']) ? '#' . $parsedUrl['fragment'] : '';
return $scheme . $user . $pass . $host . $port . $path . $query . $fragment;
}
private function getRedirectUrl(string $location): array
{
$uri = parse_url($location);
if (isset($uri['host'])) {
$redirectUri = $uri;
} else {
if (!isset($location[0])) {
return [];
}
$redirectUri = $this->urlInfo;
$redirectUri['query'] = '';
if ($location[0] === '/') {
$redirectUri['path'] = $location;
} else {
$path = dirname($redirectUri['path'] ?? '');
if ($path === '.') {
$path = '/';
}
if (isset($location[1]) and substr($location, 0, 2) === './') {
$location = substr($location, 2);
}
$redirectUri['path'] = $path . $location;
}
foreach ($uri as $k => $v) {
if (!in_array($k, ['path', 'query'])) {
$redirectUri[$k] = $v;
}
}
}
return $redirectUri;
}
}
@@ -0,0 +1,127 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\Database;
class MysqliConfig
{
/** @var string */
protected $host = '127.0.0.1';
/** @var int */
protected $port = 3306;
/** @var null|string */
protected $unixSocket = '';
/** @var string */
protected $dbname = 'test';
/** @var string */
protected $charset = 'utf8mb4';
/** @var string */
protected $username = 'root';
/** @var string */
protected $password = 'root';
/** @var array */
protected $options = [];
public function getHost(): string
{
return $this->host;
}
public function withHost($host): self
{
$this->host = $host;
return $this;
}
public function getPort(): int
{
return $this->port;
}
public function getUnixSocket(): string
{
return $this->unixSocket;
}
public function withUnixSocket(?string $unixSocket): self
{
$this->unixSocket = $unixSocket;
return $this;
}
public function withPort(int $port): self
{
$this->port = $port;
return $this;
}
public function getDbname(): string
{
return $this->dbname;
}
public function withDbname(string $dbname): self
{
$this->dbname = $dbname;
return $this;
}
public function getCharset(): string
{
return $this->charset;
}
public function withCharset(string $charset): self
{
$this->charset = $charset;
return $this;
}
public function getUsername(): string
{
return $this->username;
}
public function withUsername(string $username): self
{
$this->username = $username;
return $this;
}
public function getPassword(): string
{
return $this->password;
}
public function withPassword(string $password): self
{
$this->password = $password;
return $this;
}
public function getOptions(): array
{
return $this->options;
}
public function withOptions(array $options): self
{
$this->options = $options;
return $this;
}
}
@@ -0,0 +1,18 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\Database;
use Exception;
class MysqliException extends Exception
{
}
@@ -0,0 +1,48 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\Database;
use mysqli;
use Swoole\ConnectionPool;
/**
* @method mysqli|MysqliProxy get()
* @method void put(mysqli|MysqliProxy $connection)
*/
class MysqliPool extends ConnectionPool
{
/** @var MysqliConfig */
protected $config;
public function __construct(MysqliConfig $config, int $size = self::DEFAULT_SIZE)
{
$this->config = $config;
parent::__construct(function () {
$mysqli = new mysqli();
foreach ($this->config->getOptions() as $option => $value) {
$mysqli->set_opt($option, $value);
}
$mysqli->real_connect(
$this->config->getHost(),
$this->config->getUsername(),
$this->config->getPassword(),
$this->config->getDbname(),
$this->config->getPort(),
$this->config->getUnixSocket()
);
if ($mysqli->connect_errno) {
throw new MysqliException($mysqli->connect_error, $mysqli->connect_errno);
}
return $mysqli;
}, $size, MysqliProxy::class);
}
}
@@ -0,0 +1,126 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\Database;
use mysqli;
class MysqliProxy extends ObjectProxy
{
public const IO_METHOD_REGEX = '/^autocommit|begin_transaction|change_user|close|commit|kill|multi_query|ping|prepare|query|real_connect|real_query|reap_async_query|refresh|release_savepoint|rollback|savepoint|select_db|send_query|set_charset|ssl_set$/i';
public const IO_ERRORS = [
2002, // MYSQLND_CR_CONNECTION_ERROR
2006, // MYSQLND_CR_SERVER_GONE_ERROR
2013, // MYSQLND_CR_SERVER_LOST
];
/** @var mysqli */
protected $__object;
/** @var string */
protected $charsetContext;
/** @var null|array */
protected $setOptContext;
/** @var null|array */
protected $changeUserContext;
/** @var callable */
protected $constructor;
/** @var int */
protected $round = 0;
public function __construct(callable $constructor)
{
parent::__construct($constructor());
$this->constructor = $constructor;
}
public function __call(string $name, array $arguments)
{
for ($n = 3; $n--;) {
$ret = @$this->__object->{$name}(...$arguments);
if ($ret === false) {
/* non-IO method */
if (!preg_match(static::IO_METHOD_REGEX, $name)) {
break;
}
/* no more chances or non-IO failures */
if (
!in_array($this->__object->errno, static::IO_ERRORS, true) ||
$n === 0
) {
throw new MysqliException($this->__object->error, $this->__object->errno);
}
$this->reconnect();
continue;
}
if (strcasecmp($name, 'prepare') === 0) {
$ret = new MysqliStatementProxy($ret, $arguments[0], $this);
} elseif (strcasecmp($name, 'stmt_init') === 0) {
$ret = new MysqliStatementProxy($ret, null, $this);
}
break;
}
/* @noinspection PhpUndefinedVariableInspection */
return $ret;
}
public function getRound(): int
{
return $this->round;
}
public function reconnect(): void
{
$constructor = $this->constructor;
parent::__construct($constructor());
$this->round++;
/* restore context */
if ($this->charsetContext) {
$this->__object->set_charset($this->charsetContext);
}
if ($this->setOptContext) {
foreach ($this->setOptContext as $opt => $val) {
$this->__object->set_opt($opt, $val);
}
}
if ($this->changeUserContext) {
$this->__object->change_user(...$this->changeUserContext);
}
}
public function options(int $option, $value): bool
{
$this->setOptContext[$option] = $value;
return $this->__object->options($option, $value);
}
public function set_opt(int $option, $value): bool
{
return $this->options($option, $value);
}
public function set_charset(string $charset): bool
{
$this->charsetContext = $charset;
return $this->__object->set_charset($charset);
}
public function change_user(string $user, string $password, string $database): bool
{
$this->changeUserContext = [$user, $password, $database];
return $this->__object->change_user($user, $password, $database);
}
}
@@ -0,0 +1,114 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\Database;
use mysqli;
use mysqli_stmt;
class MysqliStatementProxy extends ObjectProxy
{
public const IO_METHOD_REGEX = '/^close|execute|fetch|prepare$/i';
/** @var mysqli_stmt */
protected $__object;
/** @var null|string */
protected $queryString;
/** @var null|array */
protected $attrSetContext;
/** @var null|array */
protected $bindParamContext;
/** @var null|array */
protected $bindResultContext;
/** @var Mysqli|MysqliProxy */
protected $parent;
/** @var int */
protected $parentRound;
public function __construct(mysqli_stmt $object, ?string $queryString, MysqliProxy $parent)
{
parent::__construct($object);
$this->queryString = $queryString;
$this->parent = $parent;
$this->parentRound = $parent->getRound();
}
public function __call(string $name, array $arguments)
{
for ($n = 3; $n--;) {
$ret = @$this->__object->{$name}(...$arguments);
if ($ret === false) {
/* non-IO method */
if (!preg_match(static::IO_METHOD_REGEX, $name)) {
break;
}
/* no more chances or non-IO failures or in transaction */
if (
!in_array($this->__object->errno, $this->parent::IO_ERRORS, true) ||
$n === 0
) {
throw new MysqliException($this->__object->error, $this->__object->errno);
}
if ($this->parent->getRound() === $this->parentRound) {
/* if not equal, parent has reconnected */
$this->parent->reconnect();
}
$parent = $this->parent->__getObject();
$this->__object = $this->queryString ? @$parent->prepare($this->queryString) : @$parent->stmt_init();
if ($this->__object === false) {
throw new MysqliException($parent->error, $parent->errno);
}
if ($this->bindParamContext) {
$this->__object->bind_param($this->bindParamContext[0], ...$this->bindParamContext[1]);
}
if ($this->bindResultContext) {
$this->__object->bind_result($this->bindResultContext);
}
if ($this->attrSetContext) {
foreach ($this->attrSetContext as $attr => $value) {
$this->__object->attr_set($attr, $value);
}
}
continue;
}
if (strcasecmp($name, 'prepare') === 0) {
$this->queryString = $arguments[0];
}
break;
}
/* @noinspection PhpUndefinedVariableInspection */
return $ret;
}
public function attr_set($attr, $mode): bool
{
$this->attrSetContext[$attr] = $mode;
return $this->__object->attr_set($attr, $mode);
}
public function bind_param($types, &...$arguments): bool
{
$this->bindParamContext = [$types, $arguments];
return $this->__object->bind_param($types, ...$arguments);
}
public function bind_result(&...$arguments): bool
{
$this->bindResultContext = $arguments;
return $this->__object->bind_result(...$arguments);
}
}
@@ -0,0 +1,22 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\Database;
use Error;
class ObjectProxy extends \Swoole\ObjectProxy
{
public function __clone()
{
throw new Error('Trying to clone an uncloneable database proxy object');
}
}
@@ -0,0 +1,160 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\Database;
class PDOConfig
{
public const DRIVER_MYSQL = 'mysql';
/** @var string */
protected $driver = self::DRIVER_MYSQL;
/** @var string */
protected $host = '127.0.0.1';
/** @var int */
protected $port = 3306;
/** @var null|string */
protected $unixSocket;
/** @var string */
protected $dbname = 'test';
/** @var string */
protected $charset = 'utf8mb4';
/** @var string */
protected $username = 'root';
/** @var string */
protected $password = 'root';
/** @var array */
protected $options = [];
public function getDriver(): string
{
return $this->driver;
}
public function withDriver(string $driver): self
{
$this->driver = $driver;
return $this;
}
public function getHost(): string
{
return $this->host;
}
public function withHost($host): self
{
$this->host = $host;
return $this;
}
public function getPort(): int
{
return $this->port;
}
public function hasUnixSocket(): bool
{
return isset($this->unixSocket);
}
public function getUnixSocket(): string
{
return $this->unixSocket;
}
public function withUnixSocket(?string $unixSocket): self
{
$this->unixSocket = $unixSocket;
return $this;
}
public function withPort(int $port): self
{
$this->port = $port;
return $this;
}
public function getDbname(): string
{
return $this->dbname;
}
public function withDbname(string $dbname): self
{
$this->dbname = $dbname;
return $this;
}
public function getCharset(): string
{
return $this->charset;
}
public function withCharset(string $charset): self
{
$this->charset = $charset;
return $this;
}
public function getUsername(): string
{
return $this->username;
}
public function withUsername(string $username): self
{
$this->username = $username;
return $this;
}
public function getPassword(): string
{
return $this->password;
}
public function withPassword(string $password): self
{
$this->password = $password;
return $this;
}
public function getOptions(): array
{
return $this->options;
}
public function withOptions(array $options): self
{
$this->options = $options;
return $this;
}
/**
* Returns the list of available drivers
*
* @return string[]
*/
public static function getAvailableDrivers()
{
return [
self::DRIVER_MYSQL,
];
}
}
@@ -0,0 +1,48 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\Database;
use PDO;
use Swoole\ConnectionPool;
/**
* @method PDO|PDOProxy get()
* @method void put(PDO|PDOProxy $connection)
*/
class PDOPool extends ConnectionPool
{
/** @var int */
protected $size = 64;
/** @var PDOConfig */
protected $config;
public function __construct(PDOConfig $config, int $size = self::DEFAULT_SIZE)
{
$this->config = $config;
parent::__construct(function () {
return new PDO(
"{$this->config->getDriver()}:" .
(
$this->config->hasUnixSocket() ?
"unix_socket={$this->config->getUnixSocket()};" :
"host={$this->config->getHost()};" . "port={$this->config->getPort()};"
) .
"dbname={$this->config->getDbname()};" .
"charset={$this->config->getCharset()}",
$this->config->getUsername(),
$this->config->getPassword(),
$this->config->getOptions()
);
}, $size, PDOProxy::class);
}
}
@@ -0,0 +1,109 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\Database;
use PDO;
use PDOException;
class PDOProxy extends ObjectProxy
{
public const IO_METHOD_REGEX = '/^query|prepare|exec|beginTransaction|commit|rollback$/i';
public const IO_ERRORS = [
2002, // MYSQLND_CR_CONNECTION_ERROR
2006, // MYSQLND_CR_SERVER_GONE_ERROR
2013, // MYSQLND_CR_SERVER_LOST
];
/** @var PDO */
protected $__object;
/** @var null|array */
protected $setAttributeContext;
/** @var callable */
protected $constructor;
/** @var int */
protected $round = 0;
public function __construct(callable $constructor)
{
parent::__construct($constructor());
$this->__object->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
$this->constructor = $constructor;
}
public function __call(string $name, array $arguments)
{
for ($n = 3; $n--;) {
$ret = @$this->__object->{$name}(...$arguments);
if ($ret === false) {
/* non-IO method */
if (!preg_match(static::IO_METHOD_REGEX, $name)) {
break;
}
$errorInfo = $this->__object->errorInfo();
/* no more chances or non-IO failures */
if (
!in_array($errorInfo[1], static::IO_ERRORS, true) ||
$n === 0 ||
$this->__object->inTransaction()
) {
$exception = new PDOException($errorInfo[2], $errorInfo[1]);
$exception->errorInfo = $errorInfo;
throw $exception;
}
$this->reconnect();
continue;
}
if (
strcasecmp($name, 'prepare') === 0 ||
strcasecmp($name, 'query') === 0
) {
$ret = new PDOStatementProxy($ret, $this);
}
break;
}
/* @noinspection PhpUndefinedVariableInspection */
return $ret;
}
public function getRound(): int
{
return $this->round;
}
public function reconnect(): void
{
$constructor = $this->constructor;
parent::__construct($constructor());
$this->round++;
/* restore context */
if ($this->setAttributeContext) {
foreach ($this->setAttributeContext as $attribute => $value) {
$this->__object->setAttribute($attribute, $value);
}
}
}
public function setAttribute(int $attribute, $value): bool
{
$this->setAttributeContext[$attribute] = $value;
return $this->__object->setAttribute($attribute, $value);
}
public function inTransaction(): bool
{
return $this->__object->inTransaction();
}
}
@@ -0,0 +1,150 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\Database;
use PDO;
use PDOException;
use PDOStatement;
class PDOStatementProxy extends ObjectProxy
{
/** @var PDOStatement */
protected $__object;
/** @var null|array */
protected $setAttributeContext;
/** @var null|array */
protected $setFetchModeContext;
/** @var null|array */
protected $bindParamContext;
/** @var null|array */
protected $bindColumnContext;
/** @var null|array */
protected $bindValueContext;
/** @var PDO|PDOProxy */
protected $parent;
/** @var int */
protected $parentRound;
public function __construct(PDOStatement $object, PDOProxy $parent)
{
parent::__construct($object);
$this->parent = $parent;
$this->parentRound = $parent->getRound();
}
public function __call(string $name, array $arguments)
{
for ($n = 3; $n--;) {
$ret = @$this->__object->{$name}(...$arguments);
if ($ret === false) {
/* no IO */
if (strtolower($name) !== 'execute') {
break;
}
/* no more chances or non-IO failures or in transaction */
if (
!in_array($this->__object->errorInfo()[1], $this->parent::IO_ERRORS, true) ||
$n === 0 ||
$this->parent->inTransaction()
) {
$errorInfo = $this->__object->errorInfo();
// '00000' means “no error.”, as specified by ANSI SQL and ODBC.
if ($errorInfo[0] !== '00000') {
$exception = new PDOException($errorInfo[2], $errorInfo[1]);
$exception->errorInfo = $errorInfo;
throw $exception;
}
}
if ($this->parent->getRound() === $this->parentRound) {
/* if not equal, parent has reconnected */
$this->parent->reconnect();
}
$parent = $this->parent->__getObject();
$this->__object = $parent->prepare($this->__object->queryString);
if ($this->__object === false) {
$errorInfo = $parent->errorInfo();
$exception = new PDOException($errorInfo[2], $errorInfo[1]);
$exception->errorInfo = $errorInfo;
throw $exception;
}
if ($this->setAttributeContext) {
foreach ($this->setAttributeContext as $attribute => $value) {
$this->__object->setAttribute($attribute, $value);
}
}
if ($this->setFetchModeContext) {
$this->__object->setFetchMode(...$this->setFetchModeContext);
}
if ($this->bindParamContext) {
foreach ($this->bindParamContext as $param => $item) {
$this->__object->bindParam($param, ...$item);
}
}
if ($this->bindColumnContext) {
foreach ($this->bindColumnContext as $column => $item) {
$this->__object->bindColumn($column, ...$item);
}
}
if ($this->bindValueContext) {
foreach ($this->bindValueContext as $value => $item) {
$this->__object->bindParam($value, ...$item);
}
}
continue;
}
break;
}
/* @noinspection PhpUndefinedVariableInspection */
return $ret;
}
public function setAttribute(int $attribute, $value): bool
{
$this->setAttributeContext[$attribute] = $value;
return $this->__object->setAttribute($attribute, $value);
}
public function setFetchMode(int $mode, $classNameObject = null, array $ctorarfg = []): bool
{
$this->setFetchModeContext = [$mode, $classNameObject, $ctorarfg];
if (!isset($classNameObject)) {
return $this->__object->setFetchMode($mode);
}
return $this->__object->setFetchMode($mode, $classNameObject, $ctorarfg);
}
public function bindParam($parameter, &$variable, $data_type = PDO::PARAM_STR, $length = null, $driver_options = null): bool
{
$this->bindParamContext[$parameter] = [$variable, $data_type, $length, $driver_options];
return $this->__object->bindParam($parameter, $variable, $data_type, $length, $driver_options);
}
public function bindColumn($column, &$param, $type = null, $maxlen = null, $driverdata = null): bool
{
$this->bindColumnContext[$column] = [$param, $type, $maxlen, $driverdata];
return $this->__object->bindColumn($column, $param, $type, $maxlen, $driverdata);
}
public function bindValue($parameter, $value, $data_type = PDO::PARAM_STR): bool
{
$this->bindValueContext[$parameter] = [$value, $data_type];
return $this->__object->bindValue($parameter, $value, $data_type);
}
}
@@ -0,0 +1,127 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\Database;
class RedisConfig
{
/** @var string */
protected $host = '127.0.0.1';
/** @var int */
protected $port = 6379;
/** @var float */
protected $timeout = 0.0;
/** @var string */
protected $reserved = '';
/** @var int */
protected $retry_interval = 0;
/** @var float */
protected $read_timeout = 0.0;
/** @var string */
protected $auth = '';
/** @var int */
protected $dbIndex = 0;
public function getHost()
{
return $this->host;
}
public function withHost($host): self
{
$this->host = $host;
return $this;
}
public function getPort(): int
{
return $this->port;
}
public function withPort(int $port): self
{
$this->port = $port;
return $this;
}
public function getTimeout(): float
{
return $this->timeout;
}
public function withTimeout(float $timeout): self
{
$this->timeout = $timeout;
return $this;
}
public function getReserved(): string
{
return $this->reserved;
}
public function withReserved(string $reserved): self
{
$this->reserved = $reserved;
return $this;
}
public function getRetryInterval(): int
{
return $this->retry_interval;
}
public function withRetryInterval(int $retry_interval): self
{
$this->retry_interval = $retry_interval;
return $this;
}
public function getReadTimeout(): float
{
return $this->read_timeout;
}
public function withReadTimeout(float $read_timeout): self
{
$this->read_timeout = $read_timeout;
return $this;
}
public function getAuth(): string
{
return $this->auth;
}
public function withAuth(string $auth): self
{
$this->auth = $auth;
return $this;
}
public function getDbIndex(): int
{
return $this->dbIndex;
}
public function withDbIndex(int $dbIndex): self
{
$this->dbIndex = $dbIndex;
return $this;
}
}
@@ -0,0 +1,57 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\Database;
use Redis;
use Swoole\ConnectionPool;
/**
* @method Redis get()
* @method void put(Redis $connection)
*/
class RedisPool extends ConnectionPool
{
/** @var RedisConfig */
protected $config;
public function __construct(RedisConfig $config, int $size = self::DEFAULT_SIZE)
{
$this->config = $config;
parent::__construct(function () {
$redis = new Redis();
/* Compatible with different versions of Redis extension as much as possible */
$arguments = [
$this->config->getHost(),
$this->config->getPort(),
];
if ($this->config->getTimeout() !== 0.0) {
$arguments[] = $this->config->getTimeout();
}
if ($this->config->getRetryInterval() !== 0) {
/* reserved should always be NULL */
$arguments[] = null;
$arguments[] = $this->config->getRetryInterval();
}
if ($this->config->getReadTimeout() !== 0.0) {
$arguments[] = $this->config->getReadTimeout();
}
$redis->connect(...$arguments);
if ($this->config->getAuth()) {
$redis->auth($this->config->getAuth());
}
if ($this->config->getDbIndex() !== 0) {
$redis->select($this->config->getDbIndex());
}
return $redis;
}, $size);
}
}
@@ -0,0 +1,16 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\Exception;
class ArrayKeyNotExists extends \RuntimeException
{
}
@@ -0,0 +1,94 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole;
/**
* FastCGI constants.
*/
class FastCGI
{
/**
* Number of bytes in a FCGI_Header. Future versions of the protocol
* will not reduce this number.
*/
public const HEADER_LEN = 8;
/**
* Format of FCGI_HEADER for unpacking in PHP
*/
public const HEADER_FORMAT = 'Cversion/Ctype/nrequestId/ncontentLength/CpaddingLength/Creserved';
/**
* Max content length of a record
*/
public const MAX_CONTENT_LENGTH = 65535;
/**
* Value for version component of FCGI_Header
*/
public const VERSION_1 = 1;
/**
* Values for type component of FCGI_Header
*/
public const BEGIN_REQUEST = 1;
public const ABORT_REQUEST = 2;
public const END_REQUEST = 3;
public const PARAMS = 4;
public const STDIN = 5;
public const STDOUT = 6;
public const STDERR = 7;
public const DATA = 8;
public const GET_VALUES = 9;
public const GET_VALUES_RESULT = 10;
public const UNKNOWN_TYPE = 11;
/**
* Value for requestId component of FCGI_Header
*/
public const DEFAULT_REQUEST_ID = 1;
/**
* Mask for flags component of FCGI_BeginRequestBody
*/
public const KEEP_CONN = 1;
/**
* Values for role component of FCGI_BeginRequestBody
*/
public const RESPONDER = 1;
public const AUTHORIZER = 2;
public const FILTER = 3;
/**
* Values for protocolStatus component of FCGI_EndRequestBody
*/
public const REQUEST_COMPLETE = 0;
public const CANT_MPX_CONN = 1;
public const OVERLOADED = 2;
public const UNKNOWN_ROLE = 3;
}
@@ -0,0 +1,90 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\FastCGI;
use DomainException;
use RuntimeException;
use Swoole\FastCGI;
/**
* Utility class to simplify parsing of FastCGI protocol data.
*/
class FrameParser
{
/**
* Mapping of constants to the classes
*
* @var array
*/
protected static $classMapping = [
FastCGI::BEGIN_REQUEST => FastCGI\Record\BeginRequest::class,
FastCGI::ABORT_REQUEST => FastCGI\Record\AbortRequest::class,
FastCGI::END_REQUEST => FastCGI\Record\EndRequest::class,
FastCGI::PARAMS => FastCGI\Record\Params::class,
FastCGI::STDIN => FastCGI\Record\Stdin::class,
FastCGI::STDOUT => FastCGI\Record\Stdout::class,
FastCGI::STDERR => FastCGI\Record\Stderr::class,
FastCGI::DATA => FastCGI\Record\Data::class,
FastCGI::GET_VALUES => FastCGI\Record\GetValues::class,
FastCGI::GET_VALUES_RESULT => FastCGI\Record\GetValuesResult::class,
FastCGI::UNKNOWN_TYPE => FastCGI\Record\UnknownType::class,
];
/**
* Checks if the buffer contains a valid frame to parse
*
* @param string $buffer Binary buffer
*/
public static function hasFrame(string $buffer): bool
{
$bufferLength = strlen($buffer);
if ($bufferLength < FastCGI::HEADER_LEN) {
return false;
}
$fastInfo = unpack(FastCGI::HEADER_FORMAT, $buffer);
if ($bufferLength < FastCGI::HEADER_LEN + $fastInfo['contentLength'] + $fastInfo['paddingLength']) {
return false;
}
return true;
}
/**
* Parses a frame from the binary buffer
*
* @param string $buffer Binary buffer
*
* @return Record One of the corresponding FastCGI record
*/
public static function parseFrame(string &$buffer): Record
{
$bufferLength = strlen($buffer);
if ($bufferLength < FastCGI::HEADER_LEN) {
throw new RuntimeException('Not enough data in the buffer to parse');
}
$recordHeader = unpack(FastCGI::HEADER_FORMAT, $buffer);
$recordType = $recordHeader['type'];
if (!isset(self::$classMapping[$recordType])) {
throw new DomainException("Invalid FastCGI record type {$recordType} received");
}
/** @var Record $className */
$className = self::$classMapping[$recordType];
$record = $className::unpack($buffer);
$offset = FastCGI::HEADER_LEN + $record->getContentLength() + $record->getPaddingLength();
$buffer = substr($buffer, $offset);
return $record;
}
}
@@ -0,0 +1,424 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\FastCGI;
use InvalidArgumentException;
class HttpRequest extends Request
{
protected $params = [
'REQUEST_SCHEME' => 'http',
'REQUEST_METHOD' => 'GET',
'DOCUMENT_ROOT' => '',
'SCRIPT_FILENAME' => '',
'SCRIPT_NAME' => '',
'DOCUMENT_URI' => '/',
'REQUEST_URI' => '/',
'QUERY_STRING' => '',
'CONTENT_TYPE' => 'text/plain',
'CONTENT_LENGTH' => '0',
'GATEWAY_INTERFACE' => 'CGI/1.1',
'SERVER_PROTOCOL' => 'HTTP/1.1',
'SERVER_SOFTWARE' => 'swoole/' . SWOOLE_VERSION,
'REMOTE_ADDR' => 'unknown',
'REMOTE_PORT' => '0',
'SERVER_ADDR' => 'unknown',
'SERVER_PORT' => '0',
'SERVER_NAME' => 'Swoole',
'REDIRECT_STATUS' => '200',
];
public function getScheme(): ?string
{
return $this->params['REQUEST_SCHEME'] ?? null;
}
public function withScheme(string $scheme): self
{
$this->params['REQUEST_SCHEME'] = $scheme;
return $this;
}
public function withoutScheme(): void
{
unset($this->params['REQUEST_SCHEME']);
}
public function getMethod(): ?string
{
return $this->params['REQUEST_METHOD'] ?? null;
}
public function withMethod(string $method): self
{
$this->params['REQUEST_METHOD'] = $method;
return $this;
}
public function withoutMethod(): void
{
unset($this->params['REQUEST_METHOD']);
}
public function getDocumentRoot(): ?string
{
return $this->params['DOCUMENT_ROOT'] ?? null;
}
public function withDocumentRoot(string $documentRoot): self
{
$this->params['DOCUMENT_ROOT'] = $documentRoot;
return $this;
}
public function withoutDocumentRoot(): void
{
unset($this->params['DOCUMENT_ROOT']);
}
public function getScriptFilename(): ?string
{
return $this->params['SCRIPT_FILENAME'] ?? null;
}
public function withScriptFilename(string $scriptFilename): self
{
$this->params['SCRIPT_FILENAME'] = $scriptFilename;
return $this;
}
public function withoutScriptFilename(): void
{
unset($this->params['SCRIPT_FILENAME']);
}
public function getScriptName(): ?string
{
return $this->params['SCRIPT_NAME'] ?? null;
}
public function withScriptName(string $scriptName): self
{
$this->params['SCRIPT_NAME'] = $scriptName;
return $this;
}
public function withoutScriptName(): void
{
unset($this->params['SCRIPT_NAME']);
}
public function withUri(string $uri): self
{
$info = parse_url($uri);
return $this->withRequestUri($uri)
->withDocumentUri($info['path'] ?? '')
->withQueryString($info['query'] ?? '');
}
public function getDocumentUri(): ?string
{
return $this->params['DOCUMENT_URI'] ?? null;
}
public function withDocumentUri(string $documentUri): self
{
$this->params['DOCUMENT_URI'] = $documentUri;
return $this;
}
public function withoutDocumentUri(): void
{
unset($this->params['DOCUMENT_URI']);
}
public function getRequestUri(): ?string
{
return $this->params['REQUEST_URI'] ?? null;
}
public function withRequestUri(string $requestUri): self
{
$this->params['REQUEST_URI'] = $requestUri;
return $this;
}
public function withoutRequestUri(): void
{
unset($this->params['REQUEST_URI']);
}
public function withQuery($query): self
{
if (is_array($query)) {
$query = http_build_query($query);
}
return $this->withQueryString($query);
}
public function getQueryString(): ?string
{
return $this->params['QUERY_STRING'] ?? null;
}
public function withQueryString(string $queryString): self
{
$this->params['QUERY_STRING'] = $queryString;
return $this;
}
public function withoutQueryString(): void
{
unset($this->params['QUERY_STRING']);
}
public function getContentType(): ?string
{
return $this->params['CONTENT_TYPE'] ?? null;
}
public function withContentType(string $contentType): self
{
$this->params['CONTENT_TYPE'] = $contentType;
return $this;
}
public function withoutContentType(): void
{
unset($this->params['CONTENT_TYPE']);
}
public function getContentLength(): ?int
{
return isset($this->params['CONTENT_LENGTH']) ? (int) $this->params['CONTENT_LENGTH'] : null;
}
public function withContentLength(int $contentLength): self
{
$this->params['CONTENT_LENGTH'] = (string) $contentLength;
return $this;
}
public function withoutContentLength(): void
{
unset($this->params['CONTENT_LENGTH']);
}
public function getGatewayInterface(): ?string
{
return $this->params['GATEWAY_INTERFACE'] ?? null;
}
public function withGatewayInterface(string $gatewayInterface): self
{
$this->params['GATEWAY_INTERFACE'] = $gatewayInterface;
return $this;
}
public function withoutGatewayInterface(): void
{
unset($this->params['GATEWAY_INTERFACE']);
}
public function getServerProtocol(): ?string
{
return $this->params['SERVER_PROTOCOL'] ?? null;
}
public function withServerProtocol(string $serverProtocol): self
{
$this->params['SERVER_PROTOCOL'] = $serverProtocol;
return $this;
}
public function withoutServerProtocol(): void
{
unset($this->params['SERVER_PROTOCOL']);
}
public function withProtocolVersion(string $protocolVersion): self
{
if (!is_numeric($protocolVersion)) {
throw new InvalidArgumentException('Protocol version must be numeric');
}
$this->params['SERVER_PROTOCOL'] = "HTTP/{$protocolVersion}";
return $this;
}
public function getServerSoftware(): ?string
{
return $this->params['SERVER_SOFTWARE'] ?? null;
}
public function withServerSoftware(string $serverSoftware): self
{
$this->params['SERVER_SOFTWARE'] = $serverSoftware;
return $this;
}
public function withoutServerSoftware(): void
{
unset($this->params['SERVER_SOFTWARE']);
}
public function getRemoteAddr(): ?string
{
return $this->params['REMOTE_ADDR'] ?? null;
}
public function withRemoteAddr(string $remoteAddr): self
{
$this->params['REMOTE_ADDR'] = $remoteAddr;
return $this;
}
public function withoutRemoteAddr(): void
{
unset($this->params['REMOTE_ADDR']);
}
public function getRemotePort(): ?int
{
return isset($this->params['REMOTE_PORT']) ? (int) $this->params['REMOTE_PORT'] : null;
}
public function withRemotePort(int $remotePort): self
{
$this->params['REMOTE_PORT'] = (string) $remotePort;
return $this;
}
public function withoutRemotePort(): void
{
unset($this->params['REMOTE_PORT']);
}
public function getServerAddr(): ?string
{
return $this->params['SERVER_ADDR'] ?? null;
}
public function withServerAddr(string $serverAddr): self
{
$this->params['SERVER_ADDR'] = $serverAddr;
return $this;
}
public function withoutServerAddr(): void
{
unset($this->params['SERVER_ADDR']);
}
public function getServerPort(): ?int
{
return isset($this->params['SERVER_PORT']) ? (int) $this->params['SERVER_PORT'] : null;
}
public function withServerPort(int $serverPort): self
{
$this->params['SERVER_PORT'] = (string) $serverPort;
return $this;
}
public function withoutServerPort(): void
{
unset($this->params['SERVER_PORT']);
}
public function getServerName(): ?string
{
return $this->params['SERVER_NAME'] ?? null;
}
public function withServerName(string $serverName): self
{
$this->params['SERVER_NAME'] = $serverName;
return $this;
}
public function withoutServerName(): void
{
unset($this->params['SERVER_NAME']);
}
public function getRedirectStatus(): ?string
{
return $this->params['REDIRECT_STATUS'] ?? null;
}
public function withRedirectStatus(string $redirectStatus): self
{
$this->params['REDIRECT_STATUS'] = $redirectStatus;
return $this;
}
public function withoutRedirectStatus(): void
{
unset($this->params['REDIRECT_STATUS']);
}
public function getHeader(string $name): ?string
{
return $this->params[static::convertHeaderNameToParamName($name)] ?? null;
}
public function withHeader(string $name, string $value): self
{
$this->params[static::convertHeaderNameToParamName($name)] = $value;
return $this;
}
public function withoutHeader(string $name): void
{
unset($this->params[static::convertHeaderNameToParamName($name)]);
}
public function getHeaders(): array
{
$headers = [];
foreach ($this->params as $name => $value) {
if (strpos($name, 'HTTP_') === 0) {
$headers[static::convertParamNameToHeaderName($name)] = $value;
}
}
return $headers;
}
public function withHeaders(array $headers): self
{
foreach ($headers as $name => $value) {
$this->withHeader($name, $value);
}
return $this;
}
/** @return $this */
public function withBody($body): Message
{
if (is_array($body)) {
$body = http_build_query($body);
$this->withContentType('application/x-www-form-urlencoded');
}
parent::withBody($body);
return $this->withContentLength(strlen($body));
}
protected static function convertHeaderNameToParamName(string $name)
{
return 'HTTP_' . str_replace('-', '_', strtoupper($name));
}
protected static function convertParamNameToHeaderName(string $name)
{
return ucwords(str_replace('_', '-', substr($name, strlen('HTTP_'))), '-');
}
}
@@ -0,0 +1,128 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\FastCGI;
use Swoole\Http\Status;
class HttpResponse extends Response
{
/** @var int */
protected $statusCode;
/** @var string */
protected $reasonPhrase;
/** @var array */
protected $headers = [];
/** @var array */
protected $headersMap = [];
/** @var array */
protected $setCookieHeaderLines = [];
public function __construct(array $records = [])
{
parent::__construct($records);
$body = (string) $this->getBody();
if (strlen($body) === 0) {
return;
}
$array = explode("\r\n\r\n", $body, 2); // An array that contains the HTTP headers and the body.
if (count($array) != 2) {
$this->withStatusCode(Status::BAD_GATEWAY)->withReasonPhrase('Invalid FastCGI Response')->withError($body);
return;
}
$headers = explode("\r\n", $array[0]);
$body = $array[1];
foreach ($headers as $header) {
$array = explode(':', $header, 2); // An array that contains the name and the value of an HTTP header.
if (count($array) != 2) {
continue; // Invalid HTTP header? Ignore it!
}
$name = trim($array[0]);
$value = trim($array[1]);
if (strcasecmp($name, 'Status') === 0) {
$array = explode(' ', $value, 2); // An array that contains the status code (and the reason phrase).
$statusCode = $array[0];
$reasonPhrase = $array[1] ?? null;
} elseif (strcasecmp($name, 'Set-Cookie') === 0) {
$this->withSetCookieHeaderLine($value);
} else {
$this->withHeader($name, $value);
}
}
$statusCode = (int) ($statusCode ?? Status::OK);
$reasonPhrase = (string) ($reasonPhrase ?? Status::getReasonPhrase($statusCode));
$this->withStatusCode($statusCode)->withReasonPhrase($reasonPhrase);
$this->withBody($body);
}
public function getStatusCode(): int
{
return $this->statusCode;
}
public function withStatusCode(int $statusCode): self
{
$this->statusCode = $statusCode;
return $this;
}
public function getReasonPhrase(): string
{
return $this->reasonPhrase;
}
public function withReasonPhrase(string $reasonPhrase): self
{
$this->reasonPhrase = $reasonPhrase;
return $this;
}
public function getHeader(string $name): ?string
{
$name = $this->headersMap[strtolower($name)] ?? null;
return $name ? $this->headers[$name] : null;
}
public function getHeaders(): array
{
return $this->headers;
}
public function withHeader(string $name, string $value): self
{
$this->headers[$name] = $value;
$this->headersMap[strtolower($name)] = $name;
return $this;
}
public function withHeaders(array $headers): self
{
foreach ($headers as $name => $value) {
$this->withHeader($name, $value);
}
return $this;
}
public function getSetCookieHeaderLines(): array
{
return $this->setCookieHeaderLines;
}
public function withSetCookieHeaderLine(string $value): self
{
$this->setCookieHeaderLines[] = $value;
return $this;
}
}
@@ -0,0 +1,80 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\FastCGI;
class Message
{
/** @var array */
protected $params = [];
/** @var string */
protected $body = '';
/** @var string */
protected $error = '';
public function getParam(string $name): ?string
{
return $this->params[$name] ?? null;
}
public function withParam(string $name, string $value): self
{
$this->params[$name] = $value;
return $this;
}
public function withoutParam(string $name): self
{
unset($this->params[$name]);
return $this;
}
public function getParams(): array
{
return $this->params;
}
public function withParams(array $params): self
{
$this->params = $params;
return $this;
}
public function withAddedParams(array $params): self
{
$this->params = $params + $this->params;
return $this;
}
public function getBody(): string
{
return $this->body;
}
public function withBody($body): self
{
$this->body = (string) $body;
return $this;
}
public function getError(): string
{
return $this->error;
}
public function withError(string $error): self
{
$this->error = $error;
return $this;
}
}
@@ -0,0 +1,232 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\FastCGI;
use Swoole\FastCGI;
/**
* FastCGI record.
*/
class Record
{
/**
* Identifies the FastCGI protocol version.
*
* @var int
*/
protected $version = FastCGI::VERSION_1;
/**
* Identifies the FastCGI record type, i.e. the general function that the record performs.
*
* @var int
*/
protected $type = FastCGI::UNKNOWN_TYPE;
/**
* Identifies the FastCGI request to which the record belongs.
*
* @var int
*/
protected $requestId = FastCGI::DEFAULT_REQUEST_ID;
/**
* Reserved byte for future proposes
*
* @var int
*/
protected $reserved = 0;
/**
* The number of bytes in the contentData component of the record.
*
* @var int
*/
private $contentLength = 0;
/**
* The number of bytes in the paddingData component of the record.
*
* @var int
*/
private $paddingLength = 0;
/**
* Binary data, between 0 and 65535 bytes of data, interpreted according to the record type.
*
* @var string
*/
private $contentData = '';
/**
* Padding data, between 0 and 255 bytes of data, which are ignored.
*
* @var string
*/
private $paddingData = '';
/**
* Returns the binary message representation of record
*/
final public function __toString(): string
{
$headerPacket = pack(
'CCnnCC',
$this->version,
$this->type,
$this->requestId,
$this->contentLength,
$this->paddingLength,
$this->reserved
);
$payloadPacket = $this->packPayload();
$paddingPacket = pack("a{$this->paddingLength}", $this->paddingData);
return $headerPacket . $payloadPacket . $paddingPacket;
}
/**
* Unpacks the message from the binary data buffer
*
* @param string $data Binary buffer with raw data
*
* @return static
*/
final public static function unpack(string $data): self
{
$self = new static();
[
$self->version,
$self->type,
$self->requestId,
$self->contentLength,
$self->paddingLength,
$self->reserved
] = array_values(unpack(FastCGI::HEADER_FORMAT, $data));
$payload = substr($data, FastCGI::HEADER_LEN);
self::unpackPayload($self, $payload);
if (get_called_class() !== __CLASS__ && $self->contentLength > 0) {
static::unpackPayload($self, $payload);
}
return $self;
}
/**
* Sets the content data and adjusts the length fields
*
* @return static
*/
public function setContentData(string $data): self
{
$this->contentLength = strlen($data);
if ($this->contentLength > FastCGI::MAX_CONTENT_LENGTH) {
$this->contentLength = FastCGI::MAX_CONTENT_LENGTH;
$this->contentData = substr($data, 0, FastCGI::MAX_CONTENT_LENGTH);
} else {
$this->contentData = $data;
}
$extraLength = $this->contentLength % 8;
$this->paddingLength = $extraLength ? (8 - $extraLength) : 0;
return $this;
}
/**
* Returns the context data from the record
*/
public function getContentData(): string
{
return $this->contentData;
}
/**
* Returns the version of record
*/
public function getVersion(): int
{
return $this->version;
}
/**
* Returns record type
*/
public function getType(): int
{
return $this->type;
}
/**
* Returns request ID
*/
public function getRequestId(): int
{
return $this->requestId;
}
/**
* Sets request ID
*
* There should be only one unique ID for all active requests,
* use random number or preferably resetting auto-increment.
*
* @return static
*/
public function setRequestId(int $requestId): self
{
$this->requestId = $requestId;
return $this;
}
/**
* Returns the size of content length
*/
final public function getContentLength(): int
{
return $this->contentLength;
}
/**
* Returns the size of padding length
*/
final public function getPaddingLength(): int
{
return $this->paddingLength;
}
/**
* Method to unpack the payload for the record.
*
* NB: Default implementation will be always called
*
* @param static $self Instance of current frame
* @param string $data Binary data
*/
protected static function unpackPayload($self, string $data): void
{
[
$self->contentData,
$self->paddingData
] = array_values(
unpack("a{$self->contentLength}contentData/a{$self->paddingLength}paddingData", $data)
);
}
/**
* Implementation of packing the payload
*/
protected function packPayload(): string
{
return pack("a{$this->contentLength}", $this->contentData);
}
}
@@ -0,0 +1,27 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\FastCGI\Record;
use Swoole\FastCGI;
use Swoole\FastCGI\Record;
/**
* The Web server sends a FCGI_ABORT_REQUEST record to abort a request
*/
class AbortRequest extends Record
{
public function __construct(int $requestId = 0)
{
$this->type = FastCGI::ABORT_REQUEST;
$this->setRequestId($requestId);
}
}
@@ -0,0 +1,113 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\FastCGI\Record;
use Swoole\FastCGI;
use Swoole\FastCGI\Record;
/**
* The Web server sends a FCGI_BEGIN_REQUEST record to start a request.
*/
class BeginRequest extends Record
{
/**
* The role component sets the role the Web server expects the application to play.
* The currently-defined roles are:
* FCGI_RESPONDER
* FCGI_AUTHORIZER
* FCGI_FILTER
*
* @var int
*/
protected $role = FastCGI::UNKNOWN_ROLE;
/**
* The flags component contains a bit that controls connection shutdown.
*
* flags & FCGI_KEEP_CONN:
* If zero, the application closes the connection after responding to this request.
* If not zero, the application does not close the connection after responding to this request;
* the Web server retains responsibility for the connection.
*
* @var int
*/
protected $flags;
/**
* Reserved data, 5 bytes maximum
*
* @var string
*/
protected $reserved1;
public function __construct(int $role = FastCGI::UNKNOWN_ROLE, int $flags = 0, string $reserved = '')
{
$this->type = FastCGI::BEGIN_REQUEST;
$this->role = $role;
$this->flags = $flags;
$this->reserved1 = $reserved;
$this->setContentData($this->packPayload());
}
/**
* Returns the role
*
* The role component sets the role the Web server expects the application to play.
* The currently-defined roles are:
* FCGI_RESPONDER
* FCGI_AUTHORIZER
* FCGI_FILTER
*/
public function getRole(): int
{
return $this->role;
}
/**
* Returns the flags
*
* The flags component contains a bit that controls connection shutdown.
*
* flags & FCGI_KEEP_CONN:
* If zero, the application closes the connection after responding to this request.
* If not zero, the application does not close the connection after responding to this request;
* the Web server retains responsibility for the connection.
*/
public function getFlags(): int
{
return $this->flags;
}
/**
* {@inheritdoc}
* @param static $self
*/
protected static function unpackPayload($self, string $data): void
{
[
$self->role,
$self->flags,
$self->reserved1
] = array_values(unpack('nrole/Cflags/a5reserved', $data));
}
/** {@inheritdoc} */
protected function packPayload(): string
{
return pack(
'nCa5',
$this->role,
$this->flags,
$this->reserved1
);
}
}
@@ -0,0 +1,29 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\FastCGI\Record;
use Swoole\FastCGI;
use Swoole\FastCGI\Record;
/**
* Data binary stream
*
* FCGI_DATA is a second stream record type used to send additional data to the application.
*/
class Data extends Record
{
public function __construct(string $contentData = '')
{
$this->type = FastCGI::DATA;
$this->setContentData($contentData);
}
}
@@ -0,0 +1,117 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\FastCGI\Record;
use Swoole\FastCGI;
use Swoole\FastCGI\Record;
/**
* The application sends a FCGI_END_REQUEST record to terminate a request, either because the application
* has processed the request or because the application has rejected the request.
*/
class EndRequest extends Record
{
/**
* The appStatus component is an application-level status code. Each role documents its usage of appStatus.
*
* @var int
*/
protected $appStatus = 0;
/**
* The protocolStatus component is a protocol-level status code.
*
* The possible protocolStatus values are:
* FCGI_REQUEST_COMPLETE: normal end of request.
* FCGI_CANT_MPX_CONN: rejecting a new request.
* This happens when a Web server sends concurrent requests over one connection to an application that is
* designed to process one request at a time per connection.
* FCGI_OVERLOADED: rejecting a new request.
* This happens when the application runs out of some resource, e.g. database connections.
* FCGI_UNKNOWN_ROLE: rejecting a new request.
* This happens when the Web server has specified a role that is unknown to the application.
*
* @var int
*/
protected $protocolStatus = FastCGI::REQUEST_COMPLETE;
/**
* Reserved data, 3 bytes maximum
*
* @var string
*/
protected $reserved1;
public function __construct(
int $protocolStatus = FastCGI::REQUEST_COMPLETE,
int $appStatus = 0,
string $reserved = ''
) {
$this->type = FastCGI::END_REQUEST;
$this->protocolStatus = $protocolStatus;
$this->appStatus = $appStatus;
$this->reserved1 = $reserved;
$this->setContentData($this->packPayload());
}
/**
* Returns app status
*
* The appStatus component is an application-level status code. Each role documents its usage of appStatus.
*/
public function getAppStatus(): int
{
return $this->appStatus;
}
/**
* Returns the protocol status
*
* The possible protocolStatus values are:
* FCGI_REQUEST_COMPLETE: normal end of request.
* FCGI_CANT_MPX_CONN: rejecting a new request.
* This happens when a Web server sends concurrent requests over one connection to an application that is
* designed to process one request at a time per connection.
* FCGI_OVERLOADED: rejecting a new request.
* This happens when the application runs out of some resource, e.g. database connections.
* FCGI_UNKNOWN_ROLE: rejecting a new request.
* This happens when the Web server has specified a role that is unknown to the application.
*/
public function getProtocolStatus(): int
{
return $this->protocolStatus;
}
/**
* {@inheritdoc}
* @param static $self
*/
protected static function unpackPayload($self, string $data): void
{
[
$self->appStatus,
$self->protocolStatus,
$self->reserved1
] = array_values(unpack('NappStatus/CprotocolStatus/a3reserved', $data));
}
/** {@inheritdoc} */
protected function packPayload(): string
{
return pack(
'NCa3',
$this->appStatus,
$this->protocolStatus,
$this->reserved1
);
}
}
@@ -0,0 +1,48 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\FastCGI\Record;
use Swoole\FastCGI;
/**
* GetValues API
*
* The Web server can query specific variables within the application.
* The server will typically perform a query on application startup in order to to automate certain aspects of
* system configuration.
*
* The application responds by sending a record {FCGI_GET_VALUES_RESULT, 0, ...} with the values supplied.
* If the application doesn't understand a variable name that was included in the query, it omits that name from
* the response.
*
* FCGI_GET_VALUES is designed to allow an open-ended set of variables.
*
* The initial set provides information to help the server perform application and connection management:
* FCGI_MAX_CONNS: The maximum number of concurrent transport connections this application will accept,
* e.g. "1" or "10".
* FCGI_MAX_REQS: The maximum number of concurrent requests this application will accept, e.g. "1" or "50".
* FCGI_MPXS_CONNS: "0" if this application does not multiplex connections (i.e. handle concurrent requests
* over each connection), "1" otherwise.
*/
class GetValues extends Params
{
/**
* Constructs a request
*
* @param array $keys List of keys to receive
*/
public function __construct(array $keys = [])
{
parent::__construct(array_fill_keys($keys, ''));
$this->type = FastCGI::GET_VALUES;
}
}
@@ -0,0 +1,46 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\FastCGI\Record;
use Swoole\FastCGI;
/**
* GetValues API
*
* The Web server can query specific variables within the application.
* The server will typically perform a query on application startup in order to to automate certain aspects of
* system configuration.
*
* The application responds by sending a record {FCGI_GET_VALUES_RESULT, 0, ...} with the values supplied.
* If the application doesn't understand a variable name that was included in the query, it omits that name from
* the response.
*
* FCGI_GET_VALUES is designed to allow an open-ended set of variables.
*
* The initial set provides information to help the server perform application and connection management:
* FCGI_MAX_CONNS: The maximum number of concurrent transport connections this application will accept,
* e.g. "1" or "10".
* FCGI_MAX_REQS: The maximum number of concurrent requests this application will accept, e.g. "1" or "50".
* FCGI_MPXS_CONNS: "0" if this application does not multiplex connections (i.e. handle concurrent requests
* over each connection), "1" otherwise.
*/
class GetValuesResult extends Params
{
/**
* Constructs a param request
*/
public function __construct(array $values = [])
{
parent::__construct($values);
$this->type = FastCGI::GET_VALUES_RESULT;
}
}
@@ -0,0 +1,120 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\FastCGI\Record;
use Swoole\FastCGI;
use Swoole\FastCGI\Record;
/**
* Params request record
*/
class Params extends Record
{
/**
* List of params
*
* @var array
*/
protected $values = [];
/**
* Constructs a param request
*/
public function __construct(array $values = [])
{
$this->type = FastCGI::PARAMS;
$this->values = $values;
$this->setContentData($this->packPayload());
}
/**
* Returns an associative list of parameters
*/
public function getValues(): array
{
return $this->values;
}
/**
* {@inheritdoc}
* @param static $self
*/
protected static function unpackPayload($self, string $data): void
{
$currentOffset = 0;
do {
[$nameLengthHigh] = array_values(unpack('CnameLengthHigh', $data));
$isLongName = ($nameLengthHigh >> 7 == 1);
$valueOffset = $isLongName ? 4 : 1;
[$valueLengthHigh] = array_values(unpack('CvalueLengthHigh', substr($data, $valueOffset)));
$isLongValue = ($valueLengthHigh >> 7 == 1);
$dataOffset = $valueOffset + ($isLongValue ? 4 : 1);
$formatParts = [
$isLongName ? 'NnameLength' : 'CnameLength',
$isLongValue ? 'NvalueLength' : 'CvalueLength',
];
$format = join('/', $formatParts);
[$nameLength, $valueLength] = array_values(unpack($format, $data));
// Clear top bit for long record
$nameLength &= ($isLongName ? 0x7fffffff : 0x7f);
$valueLength &= ($isLongValue ? 0x7fffffff : 0x7f);
[$nameData, $valueData] = array_values(
unpack(
"a{$nameLength}nameData/a{$valueLength}valueData",
substr($data, $dataOffset)
)
);
$self->values[$nameData] = $valueData;
$keyValueLength = $dataOffset + $nameLength + $valueLength;
$data = substr($data, $keyValueLength);
$currentOffset += $keyValueLength;
} while ($currentOffset < $self->getContentLength());
}
/** {@inheritdoc} */
protected function packPayload(): string
{
$payload = '';
foreach ($this->values as $nameData => $valueData) {
if ($valueData === null) {
continue;
}
$nameLength = strlen($nameData);
$valueLength = strlen((string) $valueData);
$isLongName = $nameLength > 127;
$isLongValue = $valueLength > 127;
$formatParts = [
$isLongName ? 'N' : 'C',
$isLongValue ? 'N' : 'C',
"a{$nameLength}",
"a{$valueLength}",
];
$format = join('', $formatParts);
$payload .= pack(
$format,
$isLongName ? ($nameLength | 0x80000000) : $nameLength,
$isLongValue ? ($valueLength | 0x80000000) : $valueLength,
$nameData,
$valueData
);
}
return $payload;
}
}
@@ -0,0 +1,29 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\FastCGI\Record;
use Swoole\FastCGI;
use Swoole\FastCGI\Record;
/**
* Stderr binary stream
*
* FCGI_STDERR is a stream record for sending arbitrary data from the application to the Web server
*/
class Stderr extends Record
{
public function __construct(string $contentData = '')
{
$this->type = FastCGI::STDERR;
$this->setContentData($contentData);
}
}
@@ -0,0 +1,29 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact team@swoole.com
* @license https://github.com/swoole/library/blob/master/LICENSE
*/
declare(strict_types=1);
namespace Swoole\FastCGI\Record;
use Swoole\FastCGI;
use Swoole\FastCGI\Record;
/**
* Stdin binary stream
*
* FCGI_STDIN is a stream record type used in sending arbitrary data from the Web server to the application
*/
class Stdin extends Record
{
public function __construct(string $contentData = '')
{
$this->type = FastCGI::STDIN;
$this->setContentData($contentData);
}
}

Some files were not shown because too many files have changed in this diff Show More