如何在不同时间用相同的sha1sum重新创建PHAR文件?

边缘人

我正在开发一个命令行PHP项目,并且希望能够重新创建作为部署工件的PHAR文件。面临的挑战是,我无法创建两个具有相同sha1sum且相距超过1秒的PHAR。如果输入文件相同(即来自相同的git commit),我希望能够完全重新创建PHAR文件。

以下代码段演示了该问题:

#!/usr/bin/php
<?php
$hashes = array();
$file_names = array('file1.phar','file2.phar');

foreach ($file_names as $name) {
  if (file_exists($name)) {
    unlink($name);
  }
  $phar = new Phar($name);
  $phar->addFromString('cli.php', "cli\n");
  $hashes[]=sha1_file($name);
  // remove the sleep and the PHAR's are identical.
  sleep(1);
}
if ($hashes[0]==$hashes[1]) {
  echo "match\n";
} else {
  echo "do not match\n";
}

据我所知,PHAR清单中每个文件的“修改时间”字段始终设置为当前时间,似乎没有办法或可以覆盖它。甚至touch("phar://file1.phar/cli.php", 1413387555)给出错误:

touch(): Can not call touch() for a non-standard stream

我在ubuntu trusty的PHP 5.5.9和RHEL5的PHP 5.3上运行了上述代码,两个版本的行为方式相同,无法创建相同的PHAR文件。

为了遵循Jez Humble和David Farley的《持续部署》一书中的建议,我正在尝试执行此操作

任何帮助表示赞赏。

菲利普

Phar类当前不允许用户更改甚至无法访问修改时间。我曾想过将您的字符串存储到一个临时文件中,然后使用它touch来更改mtime,但这似乎没有任何效果。因此,您必须手动更改已创建文件中的时间戳,然后重新生成存档签名。以下是使用当前PHP版本的方法:

<?php
    $filename = "file1.phar";

    $archive = file_get_contents($filename);

    # Search for the start of the archive header
    # See http://php.net/manual/de/phar.fileformat.phar.php
    # This isn't the only valid way to write a PHAR archive, but it is what the Phar class
    # currently does, so you should be fine (The docs say that the end-of-PHP-tag is optional)
    $magic = "__HALT_COMPILER(); ?" . ">";
    $end_of_code = strpos($archive, $magic) + strlen($magic);
    $data_pos = $end_of_code;

    # Skip that header
    $data = unpack("Vmanifest_length/Vnumber_of_files/vapi_version/Vglobal_flags/Valias_length", substr($archive, $end_of_code, 18));
    $data_pos += 18 + $data["alias_length"];
    $metadata = unpack("Vlength", substr($archive, $data_pos, 4));
    $data_pos += 4 + $metadata["length"];

    for($i=0; $i<$data["number_of_files"]; $i++) {
        # Now $data_pos points to the first file
        # Files are explained here: http://php.net/manual/de/phar.fileformat.manifestfile.php
        $filename_data = unpack("Vfilename_length", substr($archive, $data_pos, 4));
        $data_pos += 4 + $filename_data["filename_length"];
        $file_data = unpack("Vuncompressed_size/Vtimestamp/Vcompressed_size/VCRC32/Vflags/Vmetadata_length", substr($archive, $data_pos, 24));
        # Change the timestamp to zeros (You can also use some other time here using pack("V", time()) instead of the zeros)
        $archive = substr($archive, 0, $data_pos + 4) . "\0\0\0\0" . substr($archive, $data_pos + 8);
        # Skip to the next file (it's _all_ the headers first, then file data)
        $data_pos += 24 + $file_data["metadata_length"];
    }

    # Regenerate the file's signature
    $sig_data = unpack("Vsigflags/C4magic", substr($archive, strlen($archive) - 8));
    if($sig_data["magic1"] == ord("G") && $sig_data["magic2"] == ord("B") && $sig_data["magic3"] == ord("M") && $sig_data["magic4"] == ord("B")) {
        if($sig_data["sigflags"] == 1) {
            # MD5
            $sig_pos = strlen($archive) - 8 - 16;
            $archive = substr($archive, 0, $sig_pos) . pack("H32", md5(substr($archive, 0, $sig_pos))) . substr($archive, $sig_pos + 16);
        }
        else {
            # SHA1
            $sig_pos = strlen($archive) - 8 - 20;
            $archive = substr($archive, 0, $sig_pos) . pack("H40", sha1(substr($archive, 0, $sig_pos))) . substr($archive, $sig_pos + 20);
        }
        # Note: The manual talks about SHA256/SHA512 support, but the according flags aren't documented yet. Currently,
        # PHAR uses SHA1 by default, so there's nothing to worry about. You still might have to add those sometime.
    }

    file_put_contents($filename, $archive);

我已经为我的本地PHP 5.5.9版本和上面的示例编写了该临时文档。该脚本适用于与上述示例代码类似创建的文件。该文档提示与该格式存在一些有效偏差。在代码的相应行中有注释;如果要支持常规的Phar文件,可能必须在此处添加一些内容。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

用`ftype = 1'重新创建XFS文件系统

来自分类Dev

如何在不同时间从Facebook请求不同的权限?

来自分类Dev

如何在Flutter中的不同时间在Sqlite数据库中创建多个表

来自分类Dev

如何在运行时每0.2秒在屏幕上的不同位置重新创建屏幕上的相同节点?

来自分类Dev

丢失.idea文件夹后,如何在Android Studio中重新创建项目?

来自分类Dev

如何在每次重新创建.pyc文件时强制Django?

来自分类Dev

丢失.idea文件夹后,如何在Android Studio中重新创建项目?

来自分类Dev

如何在ubuntu服务器中重新创建.Trash文件

来自分类Dev

如何在JAVA中重新创建竞争条件?

来自分类Dev

如何在ViewPager中重新创建片段

来自分类Dev

如何在DialogFragment中重新创建ListView

来自分类Dev

如何在ViewPager中重新创建片段

来自分类Dev

如何在viewpager中重新创建片段?

来自分类Dev

带有sha1和sha1sum的hashdeep创建不同的结果

来自分类Dev

文件的R sha1sum

来自分类Dev

目录中文件的sha1sum

来自分类Dev

目录中文件的sha1sum

来自分类Dev

如何通过在不同时间调用相同方法在文本文件中写入多行?

来自分类Dev

防止重新创建或覆盖文件

来自分类Dev

为什么sha1sum在相同输入下的行为不同?

来自分类Dev

将相同时间转换为不同时区

来自分类Dev

如何在 ClearCase 中查找新创建的文件

来自分类Dev

如何重新创建以前的活动?

来自分类Dev

如何重新创建片段?

来自分类Dev

SQLAlchemy:如何重新创建表

来自分类Dev

WPF:如何重新创建 ItemContainer?

来自分类Dev

LogStash:如何在保持相同时间格式的同时复制@timestamp字段?

来自分类Dev

在先前的SHA上重新创建远程分支

来自分类Dev

为什么每次运行该代码都会重新创建相同的文件?

Related 相关文章

  1. 1

    用`ftype = 1'重新创建XFS文件系统

  2. 2

    如何在不同时间从Facebook请求不同的权限?

  3. 3

    如何在Flutter中的不同时间在Sqlite数据库中创建多个表

  4. 4

    如何在运行时每0.2秒在屏幕上的不同位置重新创建屏幕上的相同节点?

  5. 5

    丢失.idea文件夹后,如何在Android Studio中重新创建项目?

  6. 6

    如何在每次重新创建.pyc文件时强制Django?

  7. 7

    丢失.idea文件夹后,如何在Android Studio中重新创建项目?

  8. 8

    如何在ubuntu服务器中重新创建.Trash文件

  9. 9

    如何在JAVA中重新创建竞争条件?

  10. 10

    如何在ViewPager中重新创建片段

  11. 11

    如何在DialogFragment中重新创建ListView

  12. 12

    如何在ViewPager中重新创建片段

  13. 13

    如何在viewpager中重新创建片段?

  14. 14

    带有sha1和sha1sum的hashdeep创建不同的结果

  15. 15

    文件的R sha1sum

  16. 16

    目录中文件的sha1sum

  17. 17

    目录中文件的sha1sum

  18. 18

    如何通过在不同时间调用相同方法在文本文件中写入多行?

  19. 19

    防止重新创建或覆盖文件

  20. 20

    为什么sha1sum在相同输入下的行为不同?

  21. 21

    将相同时间转换为不同时区

  22. 22

    如何在 ClearCase 中查找新创建的文件

  23. 23

    如何重新创建以前的活动?

  24. 24

    如何重新创建片段?

  25. 25

    SQLAlchemy:如何重新创建表

  26. 26

    WPF:如何重新创建 ItemContainer?

  27. 27

    LogStash:如何在保持相同时间格式的同时复制@timestamp字段?

  28. 28

    在先前的SHA上重新创建远程分支

  29. 29

    为什么每次运行该代码都会重新创建相同的文件?

热门标签

归档