Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Remove Pharaoh BC layer #960

Merged
merged 12 commits into from
Apr 7, 2023
10 changes: 10 additions & 0 deletions src/Pharaoh/InvalidPhar.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ public static function fileNotFound(string $file): self
);
}

public static function fileNotReadable(string $file): self
{
return new self(
sprintf(
'Could not read the file "%s".',
$file,
),
);
}

public static function forPhar(string $file, ?Throwable $previous): self
{
return new self(
Expand Down
123 changes: 9 additions & 114 deletions src/Pharaoh/Pharaoh.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,32 +46,28 @@
use KevinGH\Box\Console\Command\Extract;
use KevinGH\Box\Phar\CompressionAlgorithm;
use KevinGH\Box\Phar\PharMeta;
use KevinGH\Box\Phar\PharPhpSettings;
use OutOfBoundsException;
use ParagonIE\ConstantTime\Hex;
use Phar;
use PharData;
use RuntimeException;
use Symfony\Component\Filesystem\Path;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\PhpExecutableFinder;
use Symfony\Component\Process\Process;
use UnexpectedValueException;
use Webmozart\Assert\Assert;
use function file_exists;
use function getenv;
use function is_readable;
use function iter\mapKeys;
use function iter\toArrayWithKeys;
use function KevinGH\Box\FileSystem\copy;
use function KevinGH\Box\FileSystem\dump_file;
use function KevinGH\Box\FileSystem\make_tmp_dir;
use function KevinGH\Box\FileSystem\remove;
use function random_bytes;
use function sprintf;

// TODO: rename it to SafePhar

/**
* @private
*
Expand All @@ -85,9 +81,7 @@ final class Pharaoh
private static string $phpExecutable;

private PharMeta $meta;
private Phar|PharData $phar;
private string $tmp;
private string $temporaryTmp;
private string $file;
private string $fileName;
private array $compressionCount;
Expand All @@ -101,11 +95,13 @@ public function __construct(string $file)
{
$file = Path::canonicalize($file);

Assert::readable($file);
Assert::false(
PharPhpSettings::isReadonly(),
'Pharaoh cannot be used if phar.readonly is enabled in php.ini',
);
if (!file_exists($file)) {
throw InvalidPhar::fileNotFound($file);
}

if (!is_readable($file)) {
throw InvalidPhar::fileNotReadable($file);
}

self::initAlgorithms();
self::initStubFileName();
Expand All @@ -114,17 +110,12 @@ public function __construct(string $file)
$this->fileName = basename($file);

$this->tmp = make_tmp_dir('HumbugBox', 'Pharaoh');
$temporaryTmp = make_tmp_dir('HumbugBox', 'PharaohTemporary');

self::dumpPhar($file, $this->tmp);
[
$this->meta,
$this->files,
] = self::loadDumpedPharFiles($this->tmp);

$this->initPhar($file);

self::extractPhar($this->phar, $temporaryTmp);
}

public function __destruct()
Expand All @@ -143,27 +134,11 @@ public function __destruct()
}
}

/**
* @deprecated
*/
public function getPhar(): Phar|PharData
{
return $this->phar;
}

public function getTmp(): string
{
return $this->tmp;
}

/**
* @deprecated
*/
public function getTmpPubkey(): ?string
{
return $this->tmpPubkey;
}

public function getFile(): string
{
return $this->file;
Expand Down Expand Up @@ -211,15 +186,6 @@ public function getFilesCompressionCount(): array
return $this->compressionCount;
}

/**
* @deprecated
*/
public function getRoot(): string
{
// Do not cache the result
return 'phar://'.str_replace('\\', '/', realpath($this->phar->getPath())).'/';
}

/**
* @return array{'compression': CompressionAlgorithm, compressedSize: int}
*/
Expand Down Expand Up @@ -352,48 +318,6 @@ private static function getBoxBin(): string
return getenv('BOX_BIN') ?: $_SERVER['SCRIPT_NAME'];
}

private static function createPhar(string $file, string $tmpFile): Phar|PharData
{
try {
return new Phar($tmpFile);
} catch (UnexpectedValueException $cannotCreatePhar) {
// Continue
}

try {
return new PharData($tmpFile);
} catch (UnexpectedValueException) {
throw InvalidPhar::forPharAndPharData($file, $cannotCreatePhar);
}
}

private static function extractPhar(Phar|PharData $phar, string $tmp): void
{
// Extract the PHAR content
$phar->extractTo($tmp);

// Extract the stub; Phar::extractTo() does not do it since it
// is internal to the PHAR.
dump_file(
$tmp.DIRECTORY_SEPARATOR.self::$stubfile,
$phar->getStub(),
);
}

private static function getExtension(string $file): string
{
$lastExtension = pathinfo($file, PATHINFO_EXTENSION);
$extension = '';

while ('' !== $lastExtension) {
$extension = '.'.$lastExtension.$extension;
$file = mb_substr($file, 0, -(mb_strlen($lastExtension) + 1));
$lastExtension = pathinfo($file, PATHINFO_EXTENSION);
}

return '' === $extension ? '.phar' : $extension;
}

/**
* @param array<string, array{'compression': CompressionAlgorithm, compressedSize: int}> $filesMeta
*/
Expand All @@ -410,33 +334,4 @@ private static function calculateCompressionCount(array $filesMeta): array

return $count;
}

private function initPhar(string $file): void
{
$extension = self::getExtension($file);

// We have to give every one a different alias, or it pukes.
$alias = Hex::encode(random_bytes(16)).$extension;

$tmpFile = sys_get_temp_dir().DIRECTORY_SEPARATOR.$alias;
copy($file, $tmpFile, true);

$pubkey = $file.'.pubkey';
$tmpPubkey = $tmpFile.'.pubkey';
$hasPubkey = false;

if (file_exists($pubkey)) {
copy($pubkey, $tmpPubkey, true);

$hasPubkey = true;
}

$phar = self::createPhar($file, $tmpFile);

if (!($phar instanceof PharData) && !$hasPubkey) {
$phar->setAlias($alias);
}

$this->phar = $phar;
}
}
10 changes: 0 additions & 10 deletions tests/Console/Command/InfoTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
use KevinGH\Box\Pharaoh\InvalidPhar;
use KevinGH\Box\Platform;
use KevinGH\Box\Test\CommandTestCase;
use KevinGH\Box\Test\RequiresPharReadonlyOff;
use Phar;
use Symfony\Component\Console\Output\OutputInterface;
use function extension_loaded;
Expand All @@ -42,17 +41,8 @@
*/
class InfoTest extends CommandTestCase
{
use RequiresPharReadonlyOff;

private const FIXTURES = __DIR__.'/../../../fixtures/info';

protected function setUp(): void
{
$this->markAsSkippedIfPharReadonlyIsOn();

parent::setUp();
}

protected function getCommand(): Command
{
return new Info();
Expand Down
8 changes: 0 additions & 8 deletions tests/Pharaoh/PharaohTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
namespace KevinGH\Box\Pharaoh;

use KevinGH\Box\Phar\CompressionAlgorithm;
use KevinGH\Box\Test\RequiresPharReadonlyOff;
use PHPUnit\Framework\TestCase;
use function array_keys;
use function basename;
Expand All @@ -31,15 +30,8 @@
*/
final class PharaohTest extends TestCase
{
use RequiresPharReadonlyOff;

private const FIXTURES_DIR = __DIR__.'/../../fixtures';

protected function setUp(): void
{
$this->markAsSkippedIfPharReadonlyIsOn();
}

/**
* @dataProvider fileProvider
*/
Expand Down