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
8 changes: 8 additions & 0 deletions docs/capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -948,6 +948,14 @@ Auto-generated by `script/capability-matrix.php`. Do not edit by hand.
| `wordwrap` | yes | yes | yes | standard | JIT PHPT; AOT PHPT |
| `zend_thread_id` | no | no | no | standard | impl present; gated (8.4.0 ref, since 8.4.0); JIT PHPT; AOT PHPT |
| `zend_version` | yes | yes | yes | standard | JIT PHPT |
| `zip_close` | yes | yes | yes | zip | |
| `zip_entry_close` | yes | yes | yes | zip | |
| `zip_entry_filesize` | yes | yes | yes | zip | |
| `zip_entry_name` | yes | yes | yes | zip | |
| `zip_entry_open` | yes | yes | yes | zip | |
| `zip_entry_read` | yes | yes | yes | zip | |
| `zip_open` | yes | yes | yes | zip | |
| `zip_read` | yes | yes | yes | zip | |
| `zlib_decode` | yes | yes | yes | standard | JIT PHPT; AOT PHPT |
| `zlib_encode` | yes | yes | yes | standard | JIT PHPT; AOT PHPT |
| `zlib_get_coding_type` | yes | yes | yes | standard | |
Expand Down
10 changes: 9 additions & 1 deletion docs/pages/capability-comparison.html
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ <h1>PHP capability comparison</h1>
</article>
<article>
<div>Stdlib builtins</div>
<strong>896</strong> / 945 full (VM+JIT+AOT)
<strong>904</strong> / 953 full (VM+JIT+AOT)
<p style="margin:0.35rem 0 0;font-size:0.88rem;color:var(--text-muted)">24 partial · 25 gaps</p>
</article>
<article>
Expand Down Expand Up @@ -1127,6 +1127,14 @@ <h2>Stdlib builtins</h2>
<tr data-support="full"><td><code>`wordwrap`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td>—</td></tr>
<tr data-support="gap"><td><code>`zend_thread_id`</code></td><td class="status-yes">yes</td><td class="status-no">no</td><td class="status-no">no</td><td class="status-no">no</td><td>—</td></tr>
<tr data-support="full"><td><code>`zend_version`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td>—</td></tr>
<tr data-support="full"><td><code>`zip_close`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td>—</td></tr>
<tr data-support="full"><td><code>`zip_entry_close`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td>—</td></tr>
<tr data-support="full"><td><code>`zip_entry_filesize`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td>—</td></tr>
<tr data-support="full"><td><code>`zip_entry_name`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td>—</td></tr>
<tr data-support="full"><td><code>`zip_entry_open`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td>—</td></tr>
<tr data-support="full"><td><code>`zip_entry_read`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td>—</td></tr>
<tr data-support="full"><td><code>`zip_open`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td>—</td></tr>
<tr data-support="full"><td><code>`zip_read`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td>—</td></tr>
<tr data-support="full"><td><code>`zlib_decode`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td>—</td></tr>
<tr data-support="full"><td><code>`zlib_encode`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td>—</td></tr>
<tr data-support="full"><td><code>`zlib_get_coding_type`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td>—</td></tr>
Expand Down
81 changes: 81 additions & 0 deletions ext/standard/VmFs.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ final class VmFs
/** @var array<int, true> bz* stream placeholders — I/O via VmBz2StreamPure (#17301) */
private static array $bzNativePlaceholders = [];

/** @var array<int, string> zip_open() archive placeholders — state in VmZipProcedural (#6370) */
private static array $zipArchivePlaceholders = [];

/** @var array<int, int> zip_read() entry placeholders — parent archive handle (#6370) */
private static array $zipEntryPlaceholders = [];

/** @var array<int, int> host stream identity => outstanding VM handle ids (#3384 pfsockopen persistent) */
private static array $hostResourceRefcounts = [];

Expand Down Expand Up @@ -1036,6 +1042,75 @@ public static function isBzNativePlaceholder(int $handle): bool
return isset(self::$bzNativePlaceholders[$handle]);
}

/**
* Register a VM stream handle for zip_open() procedural archives (#6370).
*
* @return int|false
*/
public static function adoptZipArchivePlaceholder(string $path)
{
$id = VmPhpMemoryStream::open('php://memory', 'r+b');
if (false === $id) {
return false;
}
self::$handlePaths[$id] = 'zip://'.$path;
self::$zipArchivePlaceholders[$id] = $path;

return $id;
}

public static function isZipArchivePlaceholder(int $handle): bool
{
return isset(self::$zipArchivePlaceholders[$handle]);
}

public static function releaseZipArchivePlaceholder(int $handle): void
{
if (!isset(self::$zipArchivePlaceholders[$handle])) {
return;
}
unset(self::$zipArchivePlaceholders[$handle]);
if (VmPhpMemoryStream::isValidHandle($handle)) {
VmPhpMemoryStream::close($handle);
unset(self::$handlePaths[$handle], self::$handleModes[$handle], self::$handleBlocked[$handle]);
}
}

/**
* @return int|false
*/
public static function adoptZipEntryPlaceholder(int $archiveHandle)
{
if (!isset(self::$zipArchivePlaceholders[$archiveHandle])) {
return false;
}
$id = VmPhpMemoryStream::open('php://memory', 'r+b');
if (false === $id) {
return false;
}
self::$handlePaths[$id] = 'zip-entry://'.$archiveHandle;
self::$zipEntryPlaceholders[$id] = $archiveHandle;

return $id;
}

public static function isZipEntryPlaceholder(int $handle): bool
{
return isset(self::$zipEntryPlaceholders[$handle]);
}

public static function releaseZipEntryPlaceholder(int $handle): void
{
if (!isset(self::$zipEntryPlaceholders[$handle])) {
return;
}
unset(self::$zipEntryPlaceholders[$handle]);
if (VmPhpMemoryStream::isValidHandle($handle)) {
VmPhpMemoryStream::close($handle);
unset(self::$handlePaths[$handle], self::$handleModes[$handle], self::$handleBlocked[$handle]);
}
}

public static function releaseBzNativePlaceholder(int $handle): void
{
if (!isset(self::$bzNativePlaceholders[$handle])) {
Expand Down Expand Up @@ -2391,6 +2466,12 @@ public static function resourceTypeForStreamTag(int $handle): string
if (isset(self::$bzNativePlaceholders[$handle])) {
return 'bzip2';
}
if (isset(self::$zipArchivePlaceholders[$handle])) {
return 'Zip Archive';
}
if (isset(self::$zipEntryPlaceholders[$handle])) {
return 'Zip Entry';
}
if (VmPhpMemoryStream::isValidHandle($handle)) {
return 'stream';
}
Expand Down
7 changes: 6 additions & 1 deletion ext/standard/is_resource_.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,12 @@ public static function isResource(Variable $v): bool
$handle = \PHPCompiler\VM\ResourceSupport::resolveHandle($v);

return null !== $handle
&& (VmFs::isValidHandle($handle) || VmFs::isFailedStreamHandle($handle));
&& (
VmFs::isValidHandle($handle)
|| VmFs::isFailedStreamHandle($handle)
|| VmFs::isZipArchivePlaceholder($handle)
|| VmFs::isZipEntryPlaceholder($handle)
);
}
if ($v->isDirResource()) {
$handle = \PHPCompiler\VM\ResourceSupport::resolveHandle($v);
Expand Down
27 changes: 25 additions & 2 deletions ext/zip/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
use PHPCompiler\Runtime;

/**
* zip extension module entry (php-src ext/zip/php_zip.c; issues #5869, #3337).
* zip extension module entry (php-src ext/zip/php_zip.c; issues #5869, #3337, #6370).
*
* ZipArchive uses pure-PHP store engine ({@see ZipEngine}) without libzip.
* ZipArchive uses pure-PHP store engine ({@see ZipEngine}); procedural zip_* API in {@see VmZipProcedural}.
*/
class Module extends ModuleAbstract
{
Expand All @@ -19,4 +19,27 @@ public function init(Runtime $runtime): void
parent::init($runtime);
BuiltinClasses::register($runtime->vmContext);
}

public function getExtensionName(): string
{
return 'zip';
}

public function getFunctions(): array
{
if (!ZipExtensionPolicy::advertisesExtension()) {
return [];
}

return [
new zip_open(),
new zip_close(),
new zip_read(),
new zip_entry_open(),
new zip_entry_close(),
new zip_entry_read(),
new zip_entry_name(),
new zip_entry_filesize(),
];
}
}
Loading