Skip to content

Commit

Permalink
Merge pull request #43 from kiwilan/develop
Browse files Browse the repository at this point in the history
BETA v2.3.0
  • Loading branch information
ewilan-riviere authored Mar 7, 2024
2 parents 05a077b + 3c29174 commit 28a9bae
Show file tree
Hide file tree
Showing 23 changed files with 275 additions and 50 deletions.
8 changes: 5 additions & 3 deletions .github/workflows/run-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,20 @@ jobs:
runs-on: macos-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install dependencies
continue-on-error: true
run: |
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew update
brew install p7zip
brew install rar
brew install ghostscript
brew install imagemagick
shell: bash

- name: Checkout code
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
fail-fast: true
matrix:
os: [ubuntu-latest]
php: [8.1, 8.2]
php: [8.1, 8.2, 8.3]
stability: [prefer-stable]

name: P${{ matrix.php }} - ${{ matrix.stability }} - ${{ matrix.os }}
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/run-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ jobs:
iex "& {$(irm get.scoop.sh)} -RunAsAdmin"
scoop update
scoop install 7zip
scoop install which
scoop checkup
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
which 7z
shell: powershell

- name: Checkout code
Expand Down
44 changes: 39 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ PHP package to handle archives (`.zip`, `.rar`, `.tar`, `.7z`, `.pdf`) with unif

Supports Linux, macOS and Windows.

> **Warning**
> [!WARNING]
>
> For some formats (`.rar` and `.7z`) [`rar` PHP extension](https://github.com/cataphract/php-rar) or [p7zip](https://www.7-zip.org/) binary could be necessary, see [Requirements](#requirements).
Expand All @@ -35,15 +35,15 @@ Supports Linux, macOS and Windows.
| `.7z`, `.cb7` || [`p7zip`](https://www.7-zip.org/) binary | `p7zip` binary |
| `.pdf` || Optional (for extraction) [`imagick` PHP extension](https://github.com/Imagick/imagick) | `smalot/pdfparser` |

> **Note**
> [!NOTE]
>
> Here you can read some installation guides for dependencies
>
> - [`p7zip` guide](https://gist.github.com/ewilan-riviere/85d657f9283fa6af255531d97da5d71d)
> - [`rar` PHP extension guide](https://gist.github.com/ewilan-riviere/3f4efd752905abe24fd1cd44412d9db9#winrar)
> - [`imagick` PHP extension guide](https://gist.github.com/ewilan-riviere/3f4efd752905abe24fd1cd44412d9db9#imagemagick)
> **Warning**
> [!WARNING]
>
> - **On macOS**, for `.rar` extract, you have to [install `rar` binary](https://gist.github.com/ewilan-riviere/85d657f9283fa6af255531d97da5d71d#macos) to extract files, `p7zip` not support `.rar` extraction.
> - **On Windows**, for `.pdf` extract, [`imagick` PHP extension](https://github.com/Imagick/imagick) have to work but **my tests failed on this feature**. So to extract PDF pages I advice to use [WSL](https://learn.microsoft.com/en-us/windows/wsl/install).
Expand All @@ -53,7 +53,7 @@ If you want more information, you can read section [**About**](#about).
## Features

- List files as `ArchiveItem` array
- With `getFiles()` method: list of files
- With `getFileItems()` method: list of files
- With `getFirst()` method: first file
- With `getLast()` method: last file
- With `find()` method: find first file that match with `path` property
Expand Down Expand Up @@ -91,7 +91,7 @@ With archive file (`.zip`, `.rar`, `.tar`, `.7z`, `epub`, `cbz`, `cbr`, `cb7`, `
```php
$archive = Archive::read('path/to/archive.zip');

$files = $archive->getFiles(); // ArchiveItem[]
$files = $archive->getFileItems(); // ArchiveItem[]
$count = $archive->getCount(); // int of files count

$images = $archive->filter('jpeg'); // ArchiveItem[] with `jpeg` in their path
Expand All @@ -113,6 +113,40 @@ $content = $archive->getContents($archive->getFirst()); // PDF page as image
$text = $archive->getText($archive->getFirst()); // PDF page as text
```

### Read from string

You can read archive from string with `readFromString` method.

```php
$archive = Archive::readFromString($string);
```

This method will try to detect the format of the archive from the string. If you have an error, you can use `readFromString` method with third argument to specify the format of the archive.

```php
$archive = Archive::readFromString($string, extension: 'zip');
```

### Password protected

You can read password protected archives with `read` or `readFromString` method.

> [!WARNING]
>
> Works only with archives and not with PDF files.
```php
$archive = Archive::read('path/to/password-protected-archive.zip', 'password');
```

### Override binary path

For `p7zip` binary, you can override the path with `overrideBinaryPath` method.

```php
$archive = Archive::read($path)->overrideBinaryPath('/opt/homebrew/bin/7z');
```

### Stat

From `stat` PHP function: <https://www.php.net/manual/en/function.stat.php>
Expand Down
55 changes: 50 additions & 5 deletions src/Archive.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ protected function __construct(
protected string $path,
protected string $extension,
protected ArchiveEnum $type,
protected ?string $password = null,
) {
}

/**
* Read an archive from the path.
*/
public static function read(string $path): BaseArchive
public static function read(string $path, ?string $password = null): BaseArchive
{
if (! file_exists($path)) {
throw new \Exception("File {$path} not found");
Expand All @@ -31,7 +32,7 @@ public static function read(string $path): BaseArchive
$mimeType = Archive::getMimeType($path);
$extension = pathinfo($path, PATHINFO_EXTENSION);
$type = ArchiveEnum::fromExtension($extension, $mimeType);
$self = new self($path, $extension, $type);
$self = new self($path, $extension, $type, $password);

/** @var BaseArchive */
$archive = match ($self->type) {
Expand All @@ -42,14 +43,58 @@ public static function read(string $path): BaseArchive
ArchiveEnum::pdf => ArchivePdf::class,
};

return $archive::read($self->path);
return $archive::read($self->path, $self->password);
}

/**
* Create an archive from contents.
*
* @param string $contents Contents of the archive.
* @param string|null $password Password of the archive, can be null if no password.
* @param string|null $extension Extension of the archive, can be null to detect automatically mimetype.
*/
public static function readFromString(string $contents, ?string $password = null, ?string $extension = null): BaseArchive
{
$file_info = new \finfo(FILEINFO_MIME_TYPE);
$mime_type = $file_info->buffer($contents);

$extension = match ($mime_type) {
'application/x-bzip2' => 'bz2',
'application/gzip' => 'gz',
'application/x-rar' => 'rar',
'application/epub+zip' => 'epub',
'application/pdf' => 'pdf',
'application/zip' => 'zip',
'application/x-tar' => 'tar',
'application/x-7z-compressed' => '7z',
'application/x-cbr' => 'rar',
'application/x-cbz' => 'cbz',
'application/x-cbt' => 'tar',
'application/x-cb7' => '7z',
default => null,
};

if ($extension === null) {
throw new \Exception('Archive: Error detecting extension from mime type, please add manually archive extension as third parameter of `readFromString()`.');
}

$path = tempnam(sys_get_temp_dir(), 'archive_');
rename($path, $path .= ".{$extension}"); // Rename to add extension

try {
file_put_contents($path, $contents);
} catch (\Throwable $th) {
throw new \Exception('Archive: Error creating temporary file with `readFromString()`.');
}

return self::read($path, $password);
}

/**
* Create an archive from path, allowing extensions are `zip`, `epub`, `cbz`.
*
* @param string $path Path to the archive
* @param bool $skipAllowed Skip allowed extensions check
* @param string $path Path to the archive
* @param bool $skipAllowed Skip allowed extensions check
*
* @throws \Exception
*/
Expand Down
18 changes: 9 additions & 9 deletions src/ArchiveZipCreate.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ protected function __construct(
/**
* Create a new instance of ArchiveZipCreate, allowing extensions are `zip`, `epub`, `cbz`.
*
* @param string $path Path to the archive
* @param bool $skipAllowed Skip allowed extensions check
* @param string $path Path to the archive
* @param bool $skipAllowed Skip allowed extensions check
*
* @throws \Exception
*/
Expand Down Expand Up @@ -64,16 +64,16 @@ public function getCount(): int
/**
* @return ArchiveFile[]
*/
public function getFiles(): array
public function getFileItems(): array
{
return $this->files;
}

/**
* Add a new file to the archive from existing file.
*
* @param string $outputPath Path to the file inside the archive
* @param string $pathToFile Path to the file to add
* @param string $outputPath Path to the file inside the archive
* @param string $pathToFile Path to the file to add
*/
public function addFile(string $outputPath, string $pathToFile): self
{
Expand All @@ -86,8 +86,8 @@ public function addFile(string $outputPath, string $pathToFile): self
/**
* Add a new file to the archive from string.
*
* @param string $outputPath Path to the file inside the archive
* @param string $content Content of the file to add
* @param string $outputPath Path to the file inside the archive
* @param string $content Content of the file to add
*/
public function addFromString(string $outputPath, string $content): self
{
Expand All @@ -100,8 +100,8 @@ public function addFromString(string $outputPath, string $content): self
/**
* Add a full directory to the archive, including subdirectories.
*
* @param string $relativeTo Relative path to the directory inside the archive
* @param string $path Path to the directory to add
* @param string $relativeTo Relative path to the directory inside the archive
* @param string $path Path to the directory to add
*
* ```php
* $archive->addDirectory('./to/directory', '/path/to/directory');
Expand Down
14 changes: 12 additions & 2 deletions src/Processes/SevenZipProcess.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,18 @@ class SevenZipProcess

protected function __construct(
protected string $path,
protected ?string $password = null,
protected ?string $binaryPath = null,
) {
}

public static function make(string $path): self
public static function make(string $path, ?string $password = null, ?string $binaryPath = null): self
{
if (! file_exists($path)) {
throw new Exception("File does not exist: {$path}");
}

$self = new self($path);
$self = new self($path, $password, $binaryPath);
$temp = ArchiveTemporaryDirectory::make();
$self->outputDir = $temp->path();
$self->isDarwin = PHP_OS_FAMILY === 'Darwin';
Expand Down Expand Up @@ -75,6 +77,14 @@ public function execute(string $command, array $args): array
{
SevenZipProcess::test();

if ($this->password) {
$args = ['-p'.$this->password, ...$args];
}

if ($this->binaryPath) {

}

$command = "{$command} ".implode(' ', $args);

// $process = new Process([$command, ...$args]);
Expand Down
5 changes: 4 additions & 1 deletion src/Readers/ArchivePdf.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ class ArchivePdf extends BaseArchive
{
protected string $pdfExt = 'jpg';

public static function read(string $path): self
public static function read(string $path, ?string $password = null): self
{
$self = new self();
if ($password) {
$self->password = $password;
}
$self->setup($path);
$self->parse();

Expand Down
9 changes: 8 additions & 1 deletion src/Readers/ArchivePhar.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,16 @@

class ArchivePhar extends BaseArchive
{
public static function read(string $path): self
public static function read(string $path, ?string $password = null): BaseArchive
{
$self = new self();
if ($password) {
$self->password = $password;
$self = ArchiveSevenZip::read($path, $password);

return $self;
}

$self->setup($path);
$self->parse();

Expand Down
11 changes: 7 additions & 4 deletions src/Readers/ArchiveRar.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,17 @@

class ArchiveRar extends BaseArchive
{
public static function read(string $path): BaseArchive
public static function read(string $path, ?string $password = null): BaseArchive
{
$self = new self();
if ($password) {
$self->password = $password;
}

if (! BaseArchive::extensionRarTest(false)) {
BaseArchive::binaryP7zipTest();

$self = ArchiveSevenZip::read($path);
$self = ArchiveSevenZip::read($path, $password);

return $self;
}
Expand Down Expand Up @@ -91,7 +94,7 @@ private function parse(): static
{
$this->extensionRarTest();

$archive = RarArchive::open($this->path);
$archive = RarArchive::open($this->path, $this->password);
$this->stat = ArchiveStat::make($this->path);
$this->stat->setComment($archive->getComment());
$archive->close();
Expand All @@ -111,7 +114,7 @@ private function parse(): static
*/
private function parser(Closure $closure): mixed
{
$archive = RarArchive::open($this->getPath());
$archive = RarArchive::open($this->getPath(), $this->password);

if ($archive->isBroken()) {
throw new \Exception("Archive is broken {$this->getPath()}");
Expand Down
Loading

0 comments on commit 28a9bae

Please sign in to comment.