Skip to content
Closed
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
12 changes: 0 additions & 12 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
@@ -1,17 +1,5 @@
parameters:
ignoreErrors:
-
message: '#^Deprecated in PHP 8\.4\: Parameter \#3 \$previous \(Throwable\) is implicitly nullable via default value null\.$#'
identifier: parameter.implicitlyNullable
count: 1
path: src/Exceptions/ExecutableNotFoundException.php

-
message: '#^Deprecated in PHP 8\.4\: Parameter \#2 \$value \(string\) is implicitly nullable via default value null\.$#'
identifier: parameter.implicitlyNullable
count: 1
path: src/SevenZip.php

-
message: '#^Method Verseles\\SevenZip\\SevenZip\:\:addFlag\(\) should return \$this\(Verseles\\SevenZip\\SevenZip\) but returns Verseles\\SevenZip\\SevenZip\.$#'
identifier: return.type
Expand Down
2 changes: 1 addition & 1 deletion src/Exceptions/ExecutableNotFoundException.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

class ExecutableNotFoundException extends \Exception
{
public function __construct($message = 'Executable 7z not found.', $code = 0, Throwable $previous = null)
public function __construct($message = 'Executable 7z not found.', $code = 0, ?Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
Expand Down
46 changes: 45 additions & 1 deletion src/SevenZip.php
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ public function mmt(int|bool|string $threads = "on"): self
*/
public function addFlag(
string $flag,
string $value = null,
?string $value = null,
bool $glued = false,
): self {
if ($glued && $value !== null) {
Expand Down Expand Up @@ -1463,6 +1463,50 @@ public function verify(): string
return $this->runCommand($command);
}

/**
* Renames files inside an archive.
*
* @param array $renames An associative array mapping old file names to new file names.
*
* @return string The output of the 7-Zip command.
* @throws \InvalidArgumentException If source path is not set or if renames array is empty.
*/
public function rename(array $renames): string
{
if (!$this->getSourcePath()) {
throw new \InvalidArgumentException(
"Archive file path (source) must be set",
);
}

if (empty($renames)) {
throw new \InvalidArgumentException(
"Renames array cannot be empty",
);
}

if ($this->getPassword()) {
$this->addFlag("p", $this->getPassword(), glued: true);
}

$renameArgs = [];
foreach ($renames as $old => $new) {
$renameArgs[] = $old;
$renameArgs[] = $new;
}

$command = [
$this->sevenZipPath,
"rn",
...$this->flagrize($this->getAlwaysFlags()),
...$this->flagrize($this->getCustomFlags()),
$this->getSourcePath(),
Comment on lines +1500 to +1503
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Pass archive type switch in rename command

The new rename() implementation invokes 7z rn without -t{Type}, which breaks archives this library creates with stream-like extensions (for example format('bzip2') maps to -t7z -m0=bzip2): 7-Zip misdetects .bzip2 as a raw bzip2 stream and rn returns E_NOTIMPL instead of renaming entries. I verified this behavior locally with bin/7z2403-linux-x64 (-h documents -t{Type} for rn) where the same archive fails without -t7z and succeeds with it, so rename() is currently unusable for those supported formats.

Useful? React with 👍 / 👎.

...$renameArgs,
];

return $this->runCommand($command);
}

public function getFlag(string $flag): mixed
{
return $this->customFlags[$flag] ?? null;
Expand Down
37 changes: 34 additions & 3 deletions tests/SevenZipTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -274,9 +274,34 @@ public function testVerify(string $format): void
$this->assertStringContainsString('Everything is Ok', $output);
}

#[Covers('\Verseles\SevenZip\SevenZip::extract')]
#[Covers('\Verseles\SevenZip\SevenZip::rename')]
#[DataProvider('compressAndExtractDataProvider')]
#[Depends('testVerify')]
public function testRename(string $format): void
{
$archive = $this->testDir . '/target/archive.' . $format;

if ($format === 'bzip2') {
$this->expectException(\RuntimeException::class);
}

$renames = [
'source/Avatart.svg' => 'source/Avatar_renomeado.svg',
'source/js_interop_usage.md' => 'source/js_interop_usage_renomeado.md',
];

$output = $this->sevenZip
->source(path: $archive)
->rename($renames);

if ($format !== 'bzip2') {
$this->assertStringContainsString('Everything is Ok', $output);
}
}

#[Covers('\Verseles\SevenZip\SevenZip::extract')]
#[DataProvider('compressAndExtractDataProvider')]
#[Depends('testRename')]
public function testExtract(string $format): void
{
$archive = $this->testDir . '/target/archive.' . $format;
Expand All @@ -287,8 +312,14 @@ public function testExtract(string $format): void
->source(path: $archive)
->target(path: $target)
->extract();
$this->assertFileExists(filename: $target . '/source/Avatart.svg');
$this->assertFileExists(filename: $target . '/source/js_interop_usage.md');

if ($format !== 'bzip2') {
$this->assertFileExists(filename: $target . '/source/Avatar_renomeado.svg');
$this->assertFileExists(filename: $target . '/source/js_interop_usage_renomeado.md');
} else {
$this->assertFileExists(filename: $target . '/source/Avatart.svg');
$this->assertFileExists(filename: $target . '/source/js_interop_usage.md');
}

unlink($archive);
}
Expand Down
Loading