Completed
Push — master ( 2a17e7...e610ee )
by Arne
04:45
created

FileReader::getReadStream()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 17
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 8
nc 2
nop 1
1
<?php
2
3
namespace Storeman;
4
5
use Clue\StreamFilter;
6
use Storeman\Config\Configuration;
7
use Storeman\Hash\AggregateHashAlgorithm;
8
use Storeman\Hash\Algorithm\HashAlgorithmInterface;
9
use Storeman\Index\IndexObject;
10
11
/**
12
 * Provides read streams for index objects.
13
 */
14
class FileReader
15
{
16
    /**
17
     * @var Configuration
18
     */
19
    protected $configuration;
20
21
    /**
22
     * @var HashAlgorithmInterface[]
23
     */
24
    protected $hashFunctions;
25
26
    public function __construct(Configuration $configuration, array $hashFunctions)
27
    {
28
        $this->configuration = $configuration;
29
        $this->hashFunctions = $hashFunctions;
30
    }
31
32
    /**
33
     * Returns a readable stream for the given file index object.
34
     *
35
     * @param IndexObject $indexObject
36
     * @return resource
37
     */
38
    public function getReadStream(IndexObject $indexObject)
39
    {
40
        assert($indexObject->isFile());
41
42
        $absolutePath = "{$this->configuration->getPath()}/{$indexObject->getRelativePath()}";
43
44
        $stream = fopen($absolutePath, 'rb');
45
46
        if ($stream === false)
47
        {
48
            throw new Exception("fopen() failed for '{$absolutePath}'");
49
        }
50
51
        $this->setupStreamHashing($stream, $indexObject);
52
53
        return $stream;
54
    }
55
56
    /**
57
     * Sets up transparent file hashing.
58
     *
59
     * @param resource $stream
60
     * @param IndexObject $indexObject
61
     */
62
    protected function setupStreamHashing($stream, IndexObject $indexObject)
63
    {
64
        $knownHashes = iterator_to_array($indexObject->getHashes());
65
        $configuredHashes = $this->configuration->getFileChecksums();
66
67
        if ($missingHashes = array_diff_key($configuredHashes, $knownHashes))
68
        {
69
            $aggregateHashAlgorithm = new AggregateHashAlgorithm(array_intersect_key($this->hashFunctions, array_flip($missingHashes)));
70
            $aggregateHashAlgorithm->initialize();
71
72
            StreamFilter\prepend($stream, function(string $chunk = null) use ($aggregateHashAlgorithm, $indexObject) {
73
74
                // eof
75
                if ($chunk === null)
76
                {
77
                    $hashes = $aggregateHashAlgorithm->finalize();
78
79
                    foreach ($hashes as $algorithm => $hash)
80
                    {
81
                        $indexObject->getHashes()->addHash($algorithm, $hash);
82
                    }
83
                }
84
85
                // digest chunk
86
                else
87
                {
88
                    $aggregateHashAlgorithm->digest($chunk);
89
                }
90
91
                return $chunk;
92
            });
93
        }
94
    }
95
}
96