Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
namespace Aws\Glacier;
3
 
4
use Aws\HashInterface;
5
 
6
/**
7
 * Encapsulates the creation of a tree hash from streamed data
8
 */
9
class TreeHash implements HashInterface
10
{
11
    const MB = 1048576;
12
    const EMPTY_HASH = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855';
13
 
14
    /** @var string Algorithm used for hashing. */
15
    private $algorithm;
16
 
17
    /** @var string Buffered data that has not yet been hashed. */
18
    private $buffer;
19
 
20
    /** @var array Binary checksums from which the tree hash is derived. */
21
    private $checksums = [];
22
 
23
    /** @var string Resulting hash in binary form. */
24
    private $hash;
25
 
26
    public function __construct($algorithm = 'sha256')
27
    {
28
        $this->algorithm = $algorithm;
29
        $this->reset();
30
    }
31
 
32
    /**
33
     * {@inheritdoc}
34
     * @throws \LogicException if the root tree hash is already calculated
35
     */
36
    public function update($data)
37
    {
38
        // Error if hash is already calculated.
39
        if ($this->hash) {
40
            throw new \LogicException('You may not add more data to a '
41
                . 'complete tree hash.');
42
        }
43
 
44
        // Buffer incoming data.
45
        $this->buffer .= $data;
46
 
47
        // When there is more than a MB of data, create a checksum.
48
        while (strlen($this->buffer) >= self::MB) {
49
            $data = substr($this->buffer, 0, self::MB);
50
            $this->buffer = substr($this->buffer, self::MB) ?: '';
51
            $this->checksums[] = hash($this->algorithm, $data, true);
52
        }
53
 
54
        return $this;
55
    }
56
 
57
    /**
58
     * Add a checksum to the tree hash directly
59
     *
60
     * @param string $checksum   The checksum to add
61
     * @param bool $inBinaryForm TRUE if checksum is in binary form
62
     *
63
     * @return self
64
     * @throws \LogicException if the root tree hash is already calculated
65
     */
66
    public function addChecksum($checksum, $inBinaryForm = false)
67
    {
68
        // Error if hash is already calculated
69
        if ($this->hash) {
70
            throw new \LogicException('You may not add more checksums to a '
71
                . 'complete tree hash.');
72
        }
73
 
74
        // Convert the checksum to binary form if necessary
75
        $this->checksums[] = $inBinaryForm ? $checksum : hex2bin($checksum);
76
 
77
        return $this;
78
    }
79
 
80
    public function complete()
81
    {
82
        if (!$this->hash) {
83
            // Clear out the remaining buffer.
84
            if (strlen($this->buffer) > 0) {
85
                $this->checksums[] = hash($this->algorithm, $this->buffer, true);
86
                $this->buffer = '';
87
            }
88
 
89
            // If no hashes, add the EMPTY_HASH.
90
            if (!$this->checksums) {
91
                $this->checksums[] = hex2bin(self::EMPTY_HASH);
92
            }
93
 
94
            // Perform hashes up the tree to arrive at the root checksum.
95
            $hashes = $this->checksums;
96
            while (count($hashes) > 1) {
97
                $sets = array_chunk($hashes, 2);
98
                $hashes = array();
99
                foreach ($sets as $set) {
100
                    $hashes[] = (count($set) === 1)
101
                        ? $set[0]
102
                        : hash($this->algorithm, $set[0] . $set[1], true);
103
                }
104
            }
105
 
106
            $this->hash = $hashes[0];
107
        }
108
 
109
        return $this->hash;
110
    }
111
 
112
    public function reset()
113
    {
114
        $this->hash = null;
115
        $this->checksums = [];
116
        $this->buffer = '';
117
    }
118
}