Skip to content

Use PHP ZipArchive instead of external zip command#122

Draft
Copilot wants to merge 3 commits intomainfrom
copilot/fix-zip-command-issue
Draft

Use PHP ZipArchive instead of external zip command#122
Copilot wants to merge 3 commits intomainfrom
copilot/fix-zip-command-issue

Conversation

Copy link
Contributor

Copilot AI commented Feb 25, 2026

  • Replace external zip command with PHP's ZipArchive class in Dist_Archive_Command.php
    • Add create_zip_archive() private method that uses ZipArchive natively
    • Extract add_zip_entry() helper to eliminate duplicated file/directory adding logic
    • Refactor __invoke() to use create_zip_archive() for zip format, keep tar for targz
  • Add ext-zip to composer.json require
  • Run lint, phpcs, phpstan, phpunit to validate changes — all pass
Original prompt

This section details on the original issue you should resolve

<issue_title>'zip' is not recognized as an internal or external command, operable program or batch file.</issue_title>
<issue_description>I'm on Windows 10 and even though I can run the zip command on my terminal, I keep getting this error

'zip' is not recognized as an internal or external command, operable program or batch file.

The path for the zip.exe is already included in my PATH.

Any clues why this happens?</issue_description>

<agent_instructions>Can we use ZipArchive here?</agent_instructions>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

…upport

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix 'zip' command not recognized error on Windows 10 Use PHP ZipArchive instead of external zip command Feb 25, 2026
Copilot AI requested a review from swissspidy February 25, 2026 17:48
@codecov
Copy link

codecov bot commented Feb 25, 2026

Codecov Report

❌ Patch coverage is 90.90909% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/Dist_Archive_Command.php 90.90% 4 Missing ⚠️

📢 Thoughts on this report? Let us know!

@swissspidy

This comment was marked as resolved.

gemini-code-assist[bot]

This comment was marked as resolved.

@swissspidy

This comment was marked as resolved.

…ip_archive()

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>

This comment was marked as resolved.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request replaces the external zip command with PHP's native ZipArchive class to create ZIP archives, improving cross-platform compatibility, particularly for Windows systems where the zip command may not be available.

Changes:

  • Replaced shell command-based ZIP creation with native PHP ZipArchive implementation
  • Added ext-zip dependency to composer.json
  • Refactored __invoke() method to branch between ZIP (using ZipArchive) and tar.gz (still using shell command) formats

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/Dist_Archive_Command.php Refactored ZIP archive creation to use ZipArchive; added create_zip_archive() and add_zip_entry() helper methods; restructured control flow to handle ZIP and tar.gz formats separately
composer.json Added ext-zip extension requirement to ensure PHP ZIP support is available
Comments suppressed due to low confidence (4)

src/Dist_Archive_Command.php:488

  • If ZipArchive::open() succeeds but an exception occurs during the file/directory iteration (lines 469-486), the ZipArchive will not be properly closed. This could leave the archive file in an inconsistent state. Consider wrapping the iteration in a try-catch block and ensuring $zip->close() is called in a finally block, or at minimum calling $zip->close() before returning false on any error path.
		$zip    = new ZipArchive();
		$result = $zip->open( $archive_filepath, ZipArchive::CREATE );
		if ( true !== $result ) {
			return false;
		}

		if ( null === $included_files ) {
			$iterator = new RecursiveIteratorIterator(
				new RecursiveDirectoryIterator( $source_path, RecursiveDirectoryIterator::SKIP_DOTS ),
				RecursiveIteratorIterator::SELF_FIRST
			);
			/**
			 * @var SplFileInfo $file
			 */
			foreach ( $iterator as $file ) {
				$pathname      = $file->getPathname();
				$relative_path = substr( $pathname, strlen( $source_path ) );
				$this->add_zip_entry( $zip, $pathname, $archive_output_dir_name . str_replace( '\\', '/', $relative_path ), $file->isDir() );
			}
		} else {
			foreach ( $included_files as $relative_filepath ) {
				$full_path = $source_path . $relative_filepath;
				$this->add_zip_entry( $zip, $full_path, $archive_output_dir_name . str_replace( '\\', '/', $relative_filepath ), is_dir( $full_path ) );
			}
		}

		return $zip->close();

src/Dist_Archive_Command.php:463

  • Consider using ZipArchive::OVERWRITE flag in addition to ZipArchive::CREATE to handle file replacement more cleanly. The manual unlink call works but using ZipArchive::CREATE | ZipArchive::OVERWRITE is more idiomatic and handles edge cases better (such as the file being locked or in use). This would replace lines 458-460 with just using the combined flags on line 463.
		if ( file_exists( $archive_filepath ) ) {
			unlink( $archive_filepath );
		}

		$zip    = new ZipArchive();
		$result = $zip->open( $archive_filepath, ZipArchive::CREATE );

src/Dist_Archive_Command.php:505

  • The addFile() and addEmptyDir() methods can fail and return false (e.g., if a file is unreadable or locked). These failures are not checked, which could result in incomplete archives being created without any warning. Consider checking the return values and either logging a warning or failing with an error message that identifies which specific file or directory could not be added.
		if ( $is_dir ) {
			$zip->addEmptyDir( $archive_path );
		} else {
			$zip->addFile( $full_path, $archive_path );
		}

src/Dist_Archive_Command.php:137

  • The error message "Failed to create ZIP archive." is not very helpful for debugging. The ZipArchive::open() method returns different error codes (like ZipArchive::ER_EXISTS, ZipArchive::ER_INCONS, ZipArchive::ER_MEMORY, etc.) that could help users understand what went wrong. Consider capturing the error code from $result and providing a more specific error message, or at least logging the error code for debugging purposes.
			if ( true !== $this->create_zip_archive( $archive_absolute_filepath, $source_path, $archive_output_dir_name, $included_files ) ) {
				WP_CLI::error( 'Failed to create ZIP archive.' );

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

'zip' is not recognized as an internal or external command, operable program or batch file.

3 participants