diff --git a/generated/8.6/functionsList.php b/generated/8.6/functionsList.php
index 2177267c..03ac5199 100644
--- a/generated/8.6/functionsList.php
+++ b/generated/8.6/functionsList.php
@@ -644,6 +644,7 @@
'parse_url',
'passthru',
'pclose',
+ 'pcntl_exec',
'pcntl_getcpuaffinity',
'pcntl_getpriority',
'pcntl_setcpuaffinity',
@@ -654,9 +655,11 @@
'pcntl_sigprocmask',
'pcntl_sigtimedwait',
'pcntl_sigwaitinfo',
+ 'pcntl_unshare',
'pfsockopen',
'pg_cancel_query',
'pg_change_password',
+ 'pg_close_stmt',
'pg_connect',
'pg_connection_reset',
'pg_convert',
@@ -976,12 +979,14 @@
'ssh2_exec',
'ssh2_forward_accept',
'ssh2_forward_listen',
+ 'ssh2_keepalive_send',
'ssh2_publickey_add',
'ssh2_publickey_init',
'ssh2_publickey_remove',
'ssh2_scp_recv',
'ssh2_scp_send',
'ssh2_send_eof',
+ 'ssh2_send_signal',
'ssh2_sftp',
'ssh2_sftp_chmod',
'ssh2_sftp_lstat',
diff --git a/generated/8.6/pcntl.php b/generated/8.6/pcntl.php
index 6a1268f7..3c25d175 100644
--- a/generated/8.6/pcntl.php
+++ b/generated/8.6/pcntl.php
@@ -4,6 +4,23 @@
use Safe\Exceptions\PcntlException;
+/**
+ * @param string $path
+ * @param array $args
+ * @param array $env_vars
+ * @throws PcntlException
+ *
+ */
+function pcntl_exec(string $path, array $args = [], array $env_vars = []): void
+{
+ error_clear_last();
+ $safeResult = \pcntl_exec($path, $args, $env_vars);
+ if ($safeResult === false) {
+ throw PcntlException::createFromPhpError();
+ }
+}
+
+
/**
* @param int|null $process_id
* @return array
@@ -200,3 +217,18 @@ function pcntl_sigwaitinfo(array $signals, ?array &$info = []): int
}
return $safeResult;
}
+
+
+/**
+ * @param int $flags
+ * @throws PcntlException
+ *
+ */
+function pcntl_unshare(int $flags): void
+{
+ error_clear_last();
+ $safeResult = \pcntl_unshare($flags);
+ if ($safeResult === false) {
+ throw PcntlException::createFromPhpError();
+ }
+}
diff --git a/generated/8.6/pgsql.php b/generated/8.6/pgsql.php
index 10732a73..6f322df8 100644
--- a/generated/8.6/pgsql.php
+++ b/generated/8.6/pgsql.php
@@ -36,6 +36,24 @@ function pg_change_password(\PgSql\Connection $connection, string $user, string
}
+/**
+ * @param \PgSql\Connection $connection
+ * @param string $statement_name
+ * @return \PgSql\Result
+ * @throws PgsqlException
+ *
+ */
+function pg_close_stmt(\PgSql\Connection $connection, string $statement_name): \PgSql\Result
+{
+ error_clear_last();
+ $safeResult = \pg_close_stmt($connection, $statement_name);
+ if ($safeResult === false) {
+ throw PgsqlException::createFromPhpError();
+ }
+ return $safeResult;
+}
+
+
/**
* @param string $connection_string
* @param int $flags
diff --git a/generated/8.6/rector-migrate.php b/generated/8.6/rector-migrate.php
index 2d9ff12b..f6035d2d 100644
--- a/generated/8.6/rector-migrate.php
+++ b/generated/8.6/rector-migrate.php
@@ -652,6 +652,7 @@
'parse_url' => 'Safe\parse_url',
'passthru' => 'Safe\passthru',
'pclose' => 'Safe\pclose',
+ 'pcntl_exec' => 'Safe\pcntl_exec',
'pcntl_getcpuaffinity' => 'Safe\pcntl_getcpuaffinity',
'pcntl_getpriority' => 'Safe\pcntl_getpriority',
'pcntl_setcpuaffinity' => 'Safe\pcntl_setcpuaffinity',
@@ -662,9 +663,11 @@
'pcntl_sigprocmask' => 'Safe\pcntl_sigprocmask',
'pcntl_sigtimedwait' => 'Safe\pcntl_sigtimedwait',
'pcntl_sigwaitinfo' => 'Safe\pcntl_sigwaitinfo',
+ 'pcntl_unshare' => 'Safe\pcntl_unshare',
'pfsockopen' => 'Safe\pfsockopen',
'pg_cancel_query' => 'Safe\pg_cancel_query',
'pg_change_password' => 'Safe\pg_change_password',
+ 'pg_close_stmt' => 'Safe\pg_close_stmt',
'pg_connect' => 'Safe\pg_connect',
'pg_connection_reset' => 'Safe\pg_connection_reset',
'pg_convert' => 'Safe\pg_convert',
@@ -984,12 +987,14 @@
'ssh2_exec' => 'Safe\ssh2_exec',
'ssh2_forward_accept' => 'Safe\ssh2_forward_accept',
'ssh2_forward_listen' => 'Safe\ssh2_forward_listen',
+ 'ssh2_keepalive_send' => 'Safe\ssh2_keepalive_send',
'ssh2_publickey_add' => 'Safe\ssh2_publickey_add',
'ssh2_publickey_init' => 'Safe\ssh2_publickey_init',
'ssh2_publickey_remove' => 'Safe\ssh2_publickey_remove',
'ssh2_scp_recv' => 'Safe\ssh2_scp_recv',
'ssh2_scp_send' => 'Safe\ssh2_scp_send',
'ssh2_send_eof' => 'Safe\ssh2_send_eof',
+ 'ssh2_send_signal' => 'Safe\ssh2_send_signal',
'ssh2_sftp' => 'Safe\ssh2_sftp',
'ssh2_sftp_chmod' => 'Safe\ssh2_sftp_chmod',
'ssh2_sftp_lstat' => 'Safe\ssh2_sftp_lstat',
diff --git a/generated/8.6/ssh2.php b/generated/8.6/ssh2.php
index d09d97a8..9ccecf1b 100644
--- a/generated/8.6/ssh2.php
+++ b/generated/8.6/ssh2.php
@@ -229,6 +229,23 @@ function ssh2_forward_listen($session, int $port, ?string $host = null, int $max
}
+/**
+ * @param resource $session
+ * @return int
+ * @throws Ssh2Exception
+ *
+ */
+function ssh2_keepalive_send($session): int
+{
+ error_clear_last();
+ $safeResult = \ssh2_keepalive_send($session);
+ if ($safeResult === false) {
+ throw Ssh2Exception::createFromPhpError();
+ }
+ return $safeResult;
+}
+
+
/**
* @param resource $pkey
* @param string $algoname
@@ -336,6 +353,22 @@ function ssh2_send_eof($channel): void
}
+/**
+ * @param resource $channel
+ * @param string $signal
+ * @throws Ssh2Exception
+ *
+ */
+function ssh2_send_signal($channel, string $signal): void
+{
+ error_clear_last();
+ $safeResult = \ssh2_send_signal($channel, $signal);
+ if ($safeResult === false) {
+ throw Ssh2Exception::createFromPhpError();
+ }
+}
+
+
/**
* @param resource $sftp
* @param string $filename
diff --git a/generator/src/XmlDocParser/DocPage.php b/generator/src/XmlDocParser/DocPage.php
index 69d2255d..12c03d0a 100644
--- a/generator/src/XmlDocParser/DocPage.php
+++ b/generator/src/XmlDocParser/DocPage.php
@@ -8,7 +8,6 @@
use Safe\Generator\FileCreator;
use function explode;
-use function strpos;
class DocPage
{
@@ -113,15 +112,19 @@ public function loadAndResolveFile(): \SimpleXMLElement
}
// Load entity definitions from .ent files and build entity replacement map
- $entityReplacements = []; // Map of entity name => replacement value
-
+ $entityReplacements = [
+ 'false' => 'false',
+ 'true' => 'true',
+ 'null' => 'null',
+ ]; // Map of entity name => replacement value
+
// Load DTD-format entity files
$patterns = [
'/php/doc-base/entities/*.ent',
'/php/doc-en/*.ent',
'/php/doc-en/entities/*.ent',
];
-
+
foreach ($patterns as $pattern) {
$files = glob(PathHelper::docsDirectory() . $pattern);
if ($files !== false) {
@@ -130,7 +133,7 @@ public function loadAndResolveFile(): \SimpleXMLElement
}
}
}
-
+
// Also handle XML-format entity files (newer format)
$xmlFiles = glob(PathHelper::docsDirectory() . '/php/doc-en/entities/*.ent');
if ($xmlFiles !== false) {
@@ -155,6 +158,22 @@ public function loadAndResolveFile(): \SimpleXMLElement
}
}
+ // If php-base and php-en are out-of-sync, we get other undefined entities,
+ // let's strip those here
+ $content = (string)\preg_replace_callback(
+ '/&([a-zA-Z_][a-zA-Z0-9._-]*);/',
+ static function ($matches) {
+ $entity = $matches[1];
+ // Preserve standard XML entities
+ if (\in_array($entity, ['lt', 'gt', 'amp', 'quot', 'apos'], true)) {
+ return $matches[0];
+ }
+ // Render "undefined &url.mersenne;" as "url.mersenne"
+ return $entity;
+ },
+ $content
+ );
+
libxml_use_internal_errors(true);
$elem = \simplexml_load_string($content, \SimpleXMLElement::class, LIBXML_DTDLOAD | LIBXML_NOENT);
if ($elem === false) {
@@ -182,20 +201,20 @@ private static function parseEntityFile(string $filePath, array &$entityReplacem
if ($content === false) {
return;
}
-
+
// Remove XML declaration and comments before wrapping in DOCTYPE
$content = (string)\preg_replace('/<\?xml[^?]*\?>/', '', $content);
$content = (string)\preg_replace('//', '', $content);
-
+
// Wrap the entity declarations in a DOCTYPE so we can parse them
// This allows libxml2 to properly parse the entity declarations
$doctype = '';
$wrappedXml = '' . $doctype . '';
-
+
// Use DOMDocument to load the wrapped XML, which will parse the DTD entities
$dom = new \DOMDocument('1.0', 'utf-8');
$dom->preserveWhiteSpace = true;
-
+
libxml_use_internal_errors(true);
if ($dom->loadXML($wrappedXml)) {
// Get the internal DTD subset which contains the entity definitions
@@ -207,7 +226,7 @@ private static function parseEntityFile(string $filePath, array &$entityReplacem
}
libxml_use_internal_errors(false);
}
-
+
/**
* Extract entity definitions from a DTD internal subset string.
*
@@ -229,7 +248,7 @@ private static function extractEntitiesFromDtd(string $dtdSubset, array &$entity
}
}
}
-
+
/**
* Parse XML-format entity file (newer PHP doc format).
* These files contain ... elements.
@@ -244,11 +263,11 @@ private static function parseXmlEntityFile(string $filePath, array &$entityRepla
if ($content === false) {
return;
}
-
+
// Remove XML declaration and comments
$content = (string)\preg_replace('/<\?xml[^?]*\?>/', '', $content);
$content = (string)\preg_replace('//', '', $content);
-
+
// Extract entity elements using regex: ...
// This avoids XML parsing issues with undefined entities
if (\preg_match_all('/]*>([\s\S]*?)<\/entity>/s', $content, $matches, PREG_SET_ORDER)) {