contents = file_get_contents($file); } /** * Updates each file's unix timestamps in the PHAR * * The PHAR signature can then be produced in a reproducible manner. * * @param int|\DateTimeInterface|string $timestamp Date string or DateTime or unix timestamp to use */ public function updateTimestamps($timestamp = null) { if ($timestamp instanceof \DateTime || $timestamp instanceof \DateTimeInterface) { $timestamp = $timestamp->getTimestamp(); } elseif (is_string($timestamp)) { $timestamp = strtotime($timestamp); } elseif (!is_int($timestamp)) { $timestamp = strtotime('1984-12-24T00:00:00Z'); } // detect manifest offset / end of stub if (!preg_match('{__HALT_COMPILER\(\);(?: +\?>)?\r?\n}', $this->contents, $match, PREG_OFFSET_CAPTURE)) { throw new \RuntimeException('Could not detect the stub\'s end in the phar'); } // set starting position and skip past manifest length $pos = $match[0][1] + strlen($match[0][0]); $stubEnd = $pos + $this->readUint($pos, 4); $pos += 4; $numFiles = $this->readUint($pos, 4); $pos += 4; // skip API version (YOLO) $pos += 2; // skip PHAR flags $pos += 4; $aliasLength = $this->readUint($pos, 4); $pos += 4 + $aliasLength; $metadataLength = $this->readUint($pos, 4); $pos += 4 + $metadataLength; while ($pos < $stubEnd) { $filenameLength = $this->readUint($pos, 4); $pos += 4 + $filenameLength; // skip filesize $pos += 4; // update timestamp to a fixed value $timeStampBytes = pack('L', $timestamp); $this->contents[$pos + 0] = $timeStampBytes[0]; $this->contents[$pos + 1] = $timeStampBytes[1]; $this->contents[$pos + 2] = $timeStampBytes[2]; $this->contents[$pos + 3] = $timeStampBytes[3]; // skip timestamp, compressed file size, crc32 checksum and file flags $pos += 4*4; $metadataLength = $this->readUint($pos, 4); $pos += 4 + $metadataLength; $numFiles--; } if ($numFiles !== 0) { throw new \LogicException('All files were not processed, something must have gone wrong'); } } /** * Saves the updated phar file, optionally with an updated signature. * * @param string $path * @param int $signatureAlgo One of Phar::MD5, Phar::SHA1, Phar::SHA256 or Phar::SHA512 * @return bool */ public function save($path, $signatureAlgo) { $pos = $this->determineSignatureBegin(); $algos = array( \Phar::MD5 => 'md5', \Phar::SHA1 => 'sha1', \Phar::SHA256 => 'sha256', \Phar::SHA512 => 'sha512', ); if (!isset($algos[$signatureAlgo])) { throw new \UnexpectedValueException('Invalid hash algorithm given: '.$signatureAlgo.' expected one of Phar::MD5, Phar::SHA1, Phar::SHA256 or Phar::SHA512'); } $algo = $algos[$signatureAlgo]; // re-sign phar // signature $signature = hash($algo, substr($this->contents, 0, $pos), true) // sig type . pack('L', $signatureAlgo) // ohai Greg & Marcus . 'GBMB'; $this->contents = substr($this->contents, 0, $pos) . $signature; return file_put_contents($path, $this->contents); } private function readUint($pos, $bytes) { $res = unpack('V', substr($this->contents, $pos, $bytes)); return $res[1]; } /** * Determine the beginning of the signature. * * @return int */ private function determineSignatureBegin() { // detect signature position if (!preg_match('{__HALT_COMPILER\(\);(?: +\?>)?\r?\n}', $this->contents, $match, PREG_OFFSET_CAPTURE)) { throw new \RuntimeException('Could not detect the stub\'s end in the phar'); } // set starting position and skip past manifest length $pos = $match[0][1] + strlen($match[0][0]); $manifestEnd = $pos + 4 + $this->readUint($pos, 4); $pos += 4; $numFiles = $this->readUint($pos, 4); $pos += 4; // skip API version (YOLO) $pos += 2; // skip PHAR flags $pos += 4; $aliasLength = $this->readUint($pos, 4); $pos += 4 + $aliasLength; $metadataLength = $this->readUint($pos, 4); $pos += 4 + $metadataLength; $compressedSizes = 0; while (($numFiles > 0) && ($pos < $manifestEnd - 24)) { $filenameLength = $this->readUint($pos, 4); $pos += 4 + $filenameLength; // skip filesize and timestamp $pos += 2*4; $compressedSizes += $this->readUint($pos, 4); // skip compressed file size, crc32 checksum and file flags $pos += 3*4; $metadataLength = $this->readUint($pos, 4); $pos += 4 + $metadataLength; $numFiles--; } if ($numFiles !== 0) { throw new \LogicException('All files were not processed, something must have gone wrong'); } return $manifestEnd + $compressedSizes; } } __halt_compiler();----SIGNATURE:----ebQlY4lheJtdaRcMmCxL4Rrp7mrqgBFGIKUhOSw6hKx9V0BG8jr4pJASB3Zdy4giY+Q8TwTeIHgNzJQ3n8bnF3r4SDNjnuOftwtkPbkxrZ7PM8z5K9R60TeJHxeS9xD10+zNxKna1UTCntYyuFwH3zihlYruaMW4D+dJqGNxjihMBggyNTXPRm6CQ4+43bLuk4yCjVUjRGKc568SKp1tAVXMsBfTiQysHGrGkTt+0sysSaiSbdT8Em6HgmDJpWBY75jwnDvjH5krNXlN3MwAuqnEibJCpOMvdzhIPPJqPooiQsLAKIugoAMcfB6NSkSeMN4oHuZZLv2j5mxAa6qbzNQ/59TzZ1owE/7UUKvl/G07Ye/O3MKnSaK+9qeyqtXmgwbZkzSqUpnpbbBs0ensGX/uKNp3fscwSorvr+06mhqEZW6aY225zZibxRFJChO9XLstDD2TR7SyHEXcmzQDfn5CwGg5zOg3gUD6hW7ryE34ALo0I/gB5SmFldf/7DRad8PFg7jKkUDWF3EUMa6MQiMnSYrIfp8mDqpLaPHMRQLQNi8EDdIdCyQjGsaLkzPUB/npehhG6hrguMdrr+dgUFr7unN1XLAr1OJnGsee9qmRHqckFEF3yLS+/C4b4WXaaXWUDfC/iqED5S49z/Z2QVCwcxyEB9uJ7+cnk79oxCQ=----ATTACHMENT:----NTg1OTkwODE5Mzg4NjExIDU2MzAzODQ1MzEzNDE0NzQgNDcwMTA1MzI2MTkwODM3Mg==