Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. Timestamps.php

class Timestamps

Hierarchy

  • class \Seld\PharUtils\Timestamps

Expanded class hierarchy of Timestamps

1 file declares its use of Timestamps
Compiler.php in vendor/composer/composer/src/Composer/Compiler.php

File

vendor/seld/phar-utils/src/Timestamps.php, line 14

Namespace

Seld\PharUtils
View source
class Timestamps {
    private $contents;
    
    /**
     * @param string $file path to the phar file to use
     */
    public function __construct($file) {
        $this->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) . pack('L', $signatureAlgo) . '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;
    }

}

Members

Title Sort descending Modifiers Object type Summary
Timestamps::$contents private property
Timestamps::determineSignatureBegin private function Determine the beginning of the signature.
Timestamps::readUint private function
Timestamps::save public function Saves the updated phar file, optionally with an updated signature.
Timestamps::updateTimestamps public function Updates each file&#039;s unix timestamps in the PHAR
Timestamps::__construct public function

API Navigation

  • Drupal Core 11.1.x
  • Topics
  • Classes
  • Functions
  • Constants
  • Globals
  • Files
  • Namespaces
  • Deprecated
  • Services
RSS feed
Powered by Drupal