98 lines
2.5 KiB
PHP
98 lines
2.5 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Standalone driver for ChildFatalErrorGuardTest.
|
||
|
|
*
|
||
|
|
* Runs outside PHPUnit and Laravel on purpose: a real fatal error in a forked
|
||
|
|
* PHPUnit process would print the framework's console error rendering into
|
||
|
|
* the test output. Forks one child over a SocketPairIpc, lets it die in the
|
||
|
|
* requested way, and prints what the parent received as JSON.
|
||
|
|
*
|
||
|
|
* Usage: php fatal_child.php <oom|oom-disarmed|warning-then-exit|clean-exit>
|
||
|
|
*/
|
||
|
|
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
use BlaxSoftware\LaravelWebSockets\Ipc\SocketPairIpc;
|
||
|
|
use BlaxSoftware\LaravelWebSockets\Server\ChildFatalErrorGuard;
|
||
|
|
use BlaxSoftware\LaravelWebSockets\Websocket\ChildMessageOutcome;
|
||
|
|
use React\EventLoop\StreamSelectLoop;
|
||
|
|
|
||
|
|
require __DIR__ . '/../../../vendor/autoload.php';
|
||
|
|
|
||
|
|
$mode = $argv[1] ?? 'oom';
|
||
|
|
|
||
|
|
$loop = new StreamSelectLoop();
|
||
|
|
$ipc = SocketPairIpc::create($loop);
|
||
|
|
|
||
|
|
$pid = pcntl_fork();
|
||
|
|
|
||
|
|
if ($pid === 0) {
|
||
|
|
$ipc->setupChild();
|
||
|
|
|
||
|
|
// Stand-in for Laravel's HandleExceptions: registered earlier (in the
|
||
|
|
// server process), so it runs before the guard and sees the error first.
|
||
|
|
register_shutdown_function(function () {
|
||
|
|
$error = error_get_last();
|
||
|
|
if ($error !== null) {
|
||
|
|
fwrite(STDERR, 'app handler saw: ' . $error['message'] . "\n");
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
$frame = json_encode([
|
||
|
|
'event' => 'demo.crash:error',
|
||
|
|
'data' => ['message' => 'Internal server error', 'meta' => ['reported' => true, 'fatal' => true]],
|
||
|
|
'channel' => 'test',
|
||
|
|
]);
|
||
|
|
|
||
|
|
$guard = ChildFatalErrorGuard::register(function () use ($ipc, $frame) {
|
||
|
|
$ipc->sendToParent($frame);
|
||
|
|
});
|
||
|
|
|
||
|
|
if ($mode === 'clean-exit') {
|
||
|
|
exit(0);
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($mode === 'warning-then-exit') {
|
||
|
|
@trigger_error('just a warning', E_USER_WARNING);
|
||
|
|
exit(0);
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($mode === 'oom-disarmed') {
|
||
|
|
$guard->disarm();
|
||
|
|
}
|
||
|
|
|
||
|
|
ini_set('memory_limit', '32M');
|
||
|
|
$hog = [];
|
||
|
|
while (true) {
|
||
|
|
$hog[] = str_repeat('x', 1024 * 1024);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
$frames = [];
|
||
|
|
$outcome = new ChildMessageOutcome('demo.crash', function () {
|
||
|
|
});
|
||
|
|
|
||
|
|
$ipc->setupParent(
|
||
|
|
function ($data) use (&$frames, $outcome) {
|
||
|
|
$frames[] = $data;
|
||
|
|
$outcome->frameReceived($data);
|
||
|
|
},
|
||
|
|
function () use ($loop) {
|
||
|
|
$loop->stop();
|
||
|
|
}
|
||
|
|
);
|
||
|
|
|
||
|
|
$loop->addTimer(10, function () use ($loop) {
|
||
|
|
$loop->stop();
|
||
|
|
});
|
||
|
|
$loop->run();
|
||
|
|
|
||
|
|
pcntl_waitpid($pid, $status);
|
||
|
|
|
||
|
|
echo json_encode([
|
||
|
|
'frames' => $frames,
|
||
|
|
'exit_code' => pcntl_wifexited($status) ? pcntl_wexitstatus($status) : null,
|
||
|
|
'replied' => $outcome->replied(),
|
||
|
|
]);
|