Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
295 changes: 158 additions & 137 deletions docs/bootstrap-inventory.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ Auto-generated by `script/capability-matrix.php`. Do not edit by hand.
| `arsort` | yes | yes | yes | standard | JIT PHPT |
| `asin` | yes | yes | yes | standard | AOT PHPT |
| `asinh` | yes | yes | yes | standard | AOT PHPT |
| `asort` | yes | yes | yes | standard | JIT PHPT |
| `asort` | yes | yes | yes | standard | JIT PHPT; AOT PHPT |
| `assert` | yes | yes | yes | standard | JIT PHPT; AOT PHPT |
| `assert_options` | yes | yes | yes | standard | JIT PHPT |
| `atan` | yes | yes | yes | standard | AOT PHPT |
Expand Down
5 changes: 5 additions & 0 deletions ext/imap/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ public function init(Runtime $runtime): void
'IMAP_GC_ELT' => VmImapCore::IMAP_GC_ELT,
'IMAP_GC_ENV' => VmImapCore::IMAP_GC_ENV,
'IMAP_GC_TEXTS' => VmImapCore::IMAP_GC_TEXTS,
'IMAP_OPENTIMEOUT' => VmImapCore::IMAP_OPENTIMEOUT,
'IMAP_READTIMEOUT' => VmImapCore::IMAP_READTIMEOUT,
'IMAP_WRITETIMEOUT' => VmImapCore::IMAP_WRITETIMEOUT,
'IMAP_CLOSETIMEOUT' => VmImapCore::IMAP_CLOSETIMEOUT,
'TYPETEXT' => VmImapMailCompose::TYPETEXT,
'TYPEMULTIPART' => VmImapMailCompose::TYPEMULTIPART,
'TYPEMESSAGE' => VmImapMailCompose::TYPEMESSAGE,
Expand Down Expand Up @@ -145,6 +149,7 @@ public function getFunctions(): array
new imap_mail_compose(),
new imap_mail_copy(),
new imap_mail_move(),
new imap_timeout(),
];
}
}
73 changes: 72 additions & 1 deletion ext/imap/VmImapCore.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,22 @@ final class VmImapCore
/** @var list<string> */
private static array $alerts = [];

/** php-src PHP_IMAP_*TIMEOUT (ext/imap/php_imap.c). */
public const IMAP_OPENTIMEOUT = 1;

public const IMAP_READTIMEOUT = 2;

public const IMAP_WRITETIMEOUT = 3;

public const IMAP_CLOSETIMEOUT = 4;

/**
* Process-wide c-client timeouts (seconds); seeded from default_socket_timeout (#27680).
*
* @var array{1: int, 2: int, 3: int, 4: int}|null
*/
private static ?array $timeouts = null;

/** c-client LATT_* bits used by imap_getmailboxes() (php_imap.h). */
public const LATT_NOINFERIORS = 0x01;

Expand Down Expand Up @@ -91,6 +107,54 @@ public static function clearErrors(): void
self::$lastError = null;
}

/**
* imap_timeout() — get/set process-wide open/read/write/close timeouts (php_imap.c; #27680).
*
* @return int|bool int on get ($timeout === -1), true on successful set, false on bad type/value
*/
public static function timeout(int $timeoutType, int $timeout = -1): int|bool
{
self::ensureTimeouts();
if (-1 === $timeout) {
if (!isset(self::$timeouts[$timeoutType])) {
return false;
}

return self::$timeouts[$timeoutType];
}
if ($timeout < 0) {
return false;
}
if (!isset(self::$timeouts[$timeoutType])) {
return false;
}
self::$timeouts[$timeoutType] = $timeout;

return true;
}

/** Seconds for remote open TCP probe (php-src SET_OPENTIMEOUT / FG(default_socket_timeout)). */
public static function openTimeoutSeconds(): float
{
self::ensureTimeouts();

return (float) self::$timeouts[self::IMAP_OPENTIMEOUT];
}

private static function ensureTimeouts(): void
{
if (null !== self::$timeouts) {
return;
}
$default = (int) (\ini_get('default_socket_timeout') ?: 60);
self::$timeouts = [
self::IMAP_OPENTIMEOUT => $default,
self::IMAP_READTIMEOUT => $default,
self::IMAP_WRITETIMEOUT => $default,
self::IMAP_CLOSETIMEOUT => $default,
];
}

/**
* @return list<string>|false
*/
Expand Down Expand Up @@ -189,7 +253,14 @@ private static function openRemoteOrFail(string $mailbox, Context $ctx): Variabl

$errno = 0;
$errstr = '';
$sock = @fsockopen($host, $port, $errno, $errstr, 0.5);
// php-src uses SET_OPENTIMEOUT (default_socket_timeout); keep a floor so probes stay snappy.
$openTo = self::openTimeoutSeconds();
if ($openTo <= 0.0) {
$openTo = 0.5;
} elseif ($openTo > 2.0) {
$openTo = 2.0;
}
$sock = @fsockopen($host, $port, $errno, $errstr, $openTo);
if (false !== $sock) {
fclose($sock);
// TCP up but no IMAP client yet — treat as open failure (no c-client).
Expand Down
48 changes: 48 additions & 0 deletions ext/imap/imap_timeout.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\ext\imap;

use PHPCompiler\Frame;
use PHPCompiler\Func\Internal;
use PHPCompiler\JIT\Context;
use PHPCompiler\JIT\Variable as JITVariable;
use PHPCompiler\ext\standard\VmMath;
use PHPLLVM\Value;

/**
* imap_timeout() — get/set c-client open/read/write/close timeouts (php-src ext/imap/php_imap.c; #27680).
*/
final class imap_timeout extends Internal
{
public function __construct()
{
parent::__construct('imap_timeout');
}

public function execute(Frame $frame): void
{
$this->requireArgCountRange($frame, 'imap_timeout', 1, 2);
if (null === $frame->returnVar) {
return;
}
$timeoutType = VmMath::parseIntBuiltinArgForFrame($frame, 0, 'imap_timeout', 1, 'timeout_type');
$timeout = -1;
if (2 === \count($frame->calledArgs)) {
$timeout = VmMath::parseIntBuiltinArgForFrame($frame, 1, 'imap_timeout', 2, 'timeout');
}
$result = VmImapCore::timeout($timeoutType, $timeout);
if (\is_int($result)) {
$frame->returnVar->int($result);
} else {
$frame->returnVar->bool($result);
}
}

public function call(Context $context, JITVariable ...$args): Value
{
unset($context, $args);
throw new \LogicException('imap_timeout() is not implemented for JIT in this compiler build (issue #27680)');
}
}
2 changes: 2 additions & 0 deletions lib/BuiltinInternalArgInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,8 @@ public static function stubReturnTypeLabelForFunction(string $callableLc): ?stri
'usort', 'uasort', 'uksort', 'ksort', 'krsort' => 'true',
// ext/imap/php_imap.stub.php — InternalArgInfo return string (missing |false) (#27681, #27764, #27765)
'imap_utf7_decode', 'imap_utf8_to_mutf7', 'imap_mutf7_to_utf8', 'imap_mail_compose' => 'string|false',
// ext/imap/php_imap.stub.php — InternalArgInfo return empty; Zend int|bool (#27680)
'imap_timeout' => 'int|bool',
// ext/sysvshm/sysvshm.stub.php — InternalArgInfo return int / empty; Zend SysvSharedMemory|false / mixed (#27943)
'shm_attach' => 'SysvSharedMemory|false',
'shm_get_var' => 'mixed',
Expand Down
4 changes: 4 additions & 0 deletions lib/BuiltinInternalDefaultValues.php
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,10 @@ final class BuiltinInternalDefaultValues
'libxml_disable_entity_loader' => [
0 => ['kind' => 'bool', 'value' => true],
],
// php-src ext/imap/php_imap.stub.php — int $timeout = -1 (int infer → 0) (#27680)
'imap_timeout' => [
1 => ['kind' => 'int', 'value' => -1],
],
];

public static function isAvailable(
Expand Down
54 changes: 54 additions & 0 deletions test/compliance/cases/stdlib/imap_timeout.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
--TEST--
stdlib imap_timeout + IMAP_*TIMEOUT constants (#27680)
--ENV--
PHP_COMPILER_ENABLE_IMAP=1
--SKIPIF--
<?php
if (!\PHPCompiler\ext\imap\ImapExtensionPolicy::advertisesExtension()) {
die('skip imap withheld (#27680)');
}
?>
--FILE--
<?php
declare(strict_types=1);

echo extension_loaded('imap') ? '1' : '0';
echo function_exists('imap_timeout') ? '1' : '0';
echo defined('IMAP_OPENTIMEOUT') ? '1' : '0';
echo defined('IMAP_READTIMEOUT') ? '1' : '0';
echo defined('IMAP_WRITETIMEOUT') ? '1' : '0';
echo defined('IMAP_CLOSETIMEOUT') ? '1' : '0';
echo "\n";

echo IMAP_OPENTIMEOUT, ',', IMAP_READTIMEOUT, ',', IMAP_WRITETIMEOUT, ',', IMAP_CLOSETIMEOUT, "\n";

$rf = new ReflectionFunction('imap_timeout');
$params = $rf->getParameters();
echo $params[0]->getName(), '/', $params[1]->getName(), "\n";
echo $params[1]->isOptional() ? 'opt' : 'req', "\n";
echo $params[1]->isDefaultValueAvailable() ? (string)$params[1]->getDefaultValue() : '-', "\n";
echo $rf->hasReturnType() ? (string)$rf->getReturnType() : '-', "\n";

$open = imap_timeout(IMAP_OPENTIMEOUT);
echo is_int($open) ? 'get_int' : 'get_bad', "\n";
echo (true === imap_timeout(IMAP_OPENTIMEOUT, 42)) ? "set_ok\n" : "set_bad\n";
echo imap_timeout(IMAP_OPENTIMEOUT), "\n";
echo (true === imap_timeout(timeout_type: IMAP_READTIMEOUT, timeout: 17)) ? "named_ok\n" : "named_bad\n";
echo imap_timeout(IMAP_READTIMEOUT), "\n";
echo (false === imap_timeout(99)) ? "bad_type\n" : "bad_type_fail\n";
echo (false === imap_timeout(IMAP_OPENTIMEOUT, -5)) ? "neg_ok\n" : "neg_fail\n";
?>
--EXPECT--
111111
1,2,3,4
timeout_type/timeout
opt
-1
int|bool
get_int
set_ok
42
named_ok
17
bad_type
neg_ok
16 changes: 16 additions & 0 deletions test/repro/imap_timeout_27680.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php
declare(strict_types=1);

echo function_exists('imap_timeout') ? 'Y' : 'N', PHP_EOL;
echo defined('IMAP_OPENTIMEOUT') ? 'Y' : 'N', PHP_EOL;
echo IMAP_OPENTIMEOUT, ',', IMAP_READTIMEOUT, ',', IMAP_WRITETIMEOUT, ',', IMAP_CLOSETIMEOUT, PHP_EOL;
var_export(imap_timeout(IMAP_OPENTIMEOUT));
echo PHP_EOL;
var_export(imap_timeout(IMAP_OPENTIMEOUT, 42));
echo PHP_EOL;
var_export(imap_timeout(IMAP_OPENTIMEOUT));
echo PHP_EOL;
$rf = new ReflectionFunction('imap_timeout');
echo (string) $rf->getReturnType(), PHP_EOL;
echo $rf->getParameters()[1]->getDefaultValue(), PHP_EOL;
echo $rf->getParameters()[0]->getName(), '/', $rf->getParameters()[1]->getName(), PHP_EOL;
2 changes: 2 additions & 0 deletions test/selfhost/compiler_lib_spine_smoke/main.php
Original file line number Diff line number Diff line change
Expand Up @@ -1671,6 +1671,7 @@
require_once __DIR__.'/../../../ext/imap/imap_status.php';
require_once __DIR__.'/../../../ext/imap/imap_subscribe.php';
require_once __DIR__.'/../../../ext/imap/imap_thread.php';
require_once __DIR__.'/../../../ext/imap/imap_timeout.php';
require_once __DIR__.'/../../../ext/imap/imap_uid.php';
require_once __DIR__.'/../../../ext/imap/imap_undelete.php';
require_once __DIR__.'/../../../ext/imap/imap_unsubscribe.php';
Expand Down Expand Up @@ -5752,6 +5753,7 @@
require_once __DIR__.'/../../../lib/JIT/HashTableKeysLlvm.php';
require_once __DIR__.'/../../../lib/JIT/HashTableReverseLlvm.php';
require_once __DIR__.'/../../../lib/JIT/HashTablePadLlvm.php';
require_once __DIR__.'/../../../lib/JIT/HashTableElemLlvm.php';
require_once __DIR__.'/../../../lib/JIT/HashTableFillLlvm.php';
require_once __DIR__.'/../../../lib/JIT/HashTableCombineLlvm.php';
require_once __DIR__.'/../../../lib/JIT/HashTableMergeLlvm.php';
Expand Down
Loading