/** * Save the phar to disk. * * @param Pharchive $phar The phar to write. * * @param string $filename The file name to write to. * * @return void * * @throws \RuntimeException When the stub is illegal. */ public function save($phar, $filename) { $this->phar = $phar; $this->file = new StreamWriter($filename); $this->bins = new StreamWriter('php://temp'); $stub = $phar->getStub(); if (false === ($pos = strpos($stub, '__HALT_COMPILER();'))) { throw new \RuntimeException('Illegal stub'); } // Mimic plain PHP phar writing, it adds the closing tag. $this->file->write(substr($stub, 0, $pos + 18) . " ?>\r\n"); $this->buildManifest(); $this->file->writeStream($this->bins->seek(0)); unset($this->bins); // Now sign the phar. if ($phar->isSigned()) { $this->file->savePosition(); $this->file->seek(0); $hash = $this->file->hashStream($phar->getSignatureAlgorithm(), true); $this->file->loadPosition(); $this->file->write($hash); $this->file->writeUint32le($phar->getSignatureFlags()); $this->file->write('GBMB'); } unset($this->phar); unset($this->file); }
/** * Check the signature of the phar file. * * @return void * * @throws \RuntimeException When the signature is invalid. */ private function checkSignature() { // Validate the signature if any. if (!$this->phar->isSigned()) { return; } // Remember the cursor. $this->file->savePosition(); // Hail Greg Beaver and Marcus Bürger. if ('GBMB' !== $this->file->seek(-4, SEEK_END)->read(4)) { throw new \RuntimeException('Phar signature does not contain magic value.'); } $this->phar->setSignatureFlags($this->file->seek(-8, SEEK_END)->readUint32le()); $algorithm = $this->phar->getSignatureAlgorithm(); $length = $this->phar->getSignatureLength(); $signature = $this->file->seek(-($length + 8), SEEK_END)->read($length); $dataLength = $this->file->getLength(); $data = $this->file->seek(0)->read($dataLength - ($length + 8)); // Now validate the signature. if (hash($algorithm, $data, true) !== $signature) { throw new \RuntimeException('Invalid signature.'); } // Back to where we took off. $this->file->loadPosition(); }