FileBucket::createFromPath()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 3
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace roxblnfk\SmartStream\Data;
4
5
use InvalidArgumentException;
6
use SplFileInfo;
7
use Yiisoft\Http\Header;
8
9
class FileBucket extends DataBucket
10
{
11
    public const TYPE_OCTET_STREAM = 'application/octet-stream';
12
13
    protected const DISPOSITION_INLINE = 'inline';
14
    protected const DISPOSITION_ATTACHMENT = 'attachment';
15
16
    protected const IS_CONVERTABLE = false;
17
    protected ?string $contentType = null;
18
    protected ?string $contentDisposition = null;
19
    protected ?string $fileName = null;
20
21
    /**
22
     * FileBucket constructor.
23
     * @param string|resource|SplFileInfo $data
24
     * @param null|string $contentType
25
     * @param null|string $fileName
26
     * @throws \Exception
27
     */
28 45
    public function __construct($data, string $contentType = null, string $fileName = null)
29
    {
30
        switch (true) {
31 45
            case $data instanceof SplFileInfo:
32 6
                if (!$data->isFile()) {
33 2
                    throw new InvalidArgumentException('File does not exist or is not a file.');
34
                }
35 4
                $fileName = $fileName ?? $data->getFilename();
36
                // $contentType = $contentType ?? $this->fileContentType($data->getPathname());
37 4
                parent::__construct($data);
38 4
                break;
39 39
            case is_string($data):
40 3
            case is_resource($data):
41 38
                parent::__construct($data);
42 38
                break;
43
            default:
44 1
                throw new InvalidArgumentException(
45 1
                    'The $data parameter must be a resource, a string or an instance of SplFileInfo.'
46
                );
47
        }
48
49 42
        if ($contentType !== null) {
50 2
            $this->setContentType($contentType);
51
        }
52 42
        if ($fileName !== null) {
53 5
            $this->setAttachment($fileName);
54
        }
55 42
    }
56
57 5
    public static function createFromPath(string $filePath, string $contentType = null, string $fileName = null): self
58
    {
59 5
        return new static(new SplFileInfo($filePath), $contentType, $fileName);
60
    }
61
62 12
    public function getContentType(): ?string
63
    {
64 12
        return $this->contentType;
65
    }
66 9
    public function getFileName(): ?string
67
    {
68 9
        return $this->fileName;
69
    }
70 4
    public function hasDisposition(): bool
71
    {
72 4
        return $this->contentDisposition !== null;
73
    }
74 6
    public function isAttachment(): bool
75
    {
76 6
        return $this->contentDisposition === self::DISPOSITION_ATTACHMENT;
77
    }
78 4
    public function isInline(): bool
79
    {
80 4
        return $this->contentDisposition === self::DISPOSITION_INLINE;
81
    }
82
83 14
    public function withAttachment(string $fileName = null): self
84
    {
85 14
        $new = clone $this;
86 14
        $new->setAttachment($fileName);
87 14
        return $new;
88
    }
89 4
    public function withContentType(?string $contentType): self
90
    {
91 4
        $new = clone $this;
92 4
        $new->setContentType($contentType);
93 4
        return $new;
94
    }
95 5
    public function withInline(string $fileName = null): self
96
    {
97 5
        $new = clone $this;
98 5
        $new->setInline($fileName);
99 5
        return $new;
100
    }
101 1
    public function withoutDisposition(): self
102
    {
103 1
        $new = clone $this;
104 1
        $new->contentDisposition = null;
105 1
        $new->setDispositionHeader();
106 1
        return $new;
107
    }
108 3
    public function withAutoContentType(): self
109
    {
110 3
        $new = clone $this;
111 3
        $type = null;
112 3
        if ($new->data instanceof SplFileInfo) {
113 1
            $type = $new->fileContentType($new->data->getPathname());
114 2
        } elseif (is_string($new->data)) {
115 2
            $type = $new->bufferContentType($new->data);
116
        }
117 3
        $new->setContentType($type);
118 3
        return $new;
119
    }
120
121 8
    protected function setContentType(?string $contentType): void
122
    {
123 8
        $this->contentType = $contentType;
124 8
        $this->setHeader(Header::CONTENT_TYPE, $contentType);
125 8
    }
126 5
    protected function setInline(?string $fileName): void
127
    {
128 5
        $this->contentDisposition = self::DISPOSITION_INLINE;
129 5
        $this->fileName = $fileName;
130 5
        $this->setDispositionHeader();
131 19
    }
132
    final protected function setAttachment(?string $fileName): void
133 19
    {
134 19
        $this->contentDisposition = self::DISPOSITION_ATTACHMENT;
135 19
        $this->fileName = $fileName;
136 19
        $this->setDispositionHeader();
137 22
    }
138
    final protected function setDispositionHeader(): void
139 22
    {
140 15
        $headerBody = $this->fileName !== null
141 15
            ? sprintf(
142 15
                '%s; filename="%s"; filename*=UTF-8\'\'%s',
143 15
                $this->contentDisposition,
144 15
                preg_replace(
145
                    ['/[\x00-\x1F\x7F]/', '/["\\\\]/', '/%([a-f0-9]{2})/'],
146 22
                    [' ', '\\\\$0', '%\\\\$1'], $this->fileName),
147 22
                rawurlencode($this->fileName)
148 22
            )
149 1
            : $this->contentDisposition;
150
        $this->setHeader(Header::CONTENT_DISPOSITION, $headerBody);
151 1
    }
152
    private function fileContentType(string $filePath): ?string
153
    {
154 1
        if (!is_file($filePath) || !is_readable($filePath)) {
155
            return null;
156 2
        }
157
        return function_exists('mime_content_type') ? mime_content_type($filePath) : null;
158 2
    }
159 2
    private function bufferContentType(string $buffer): ?string
160 2
    {
161 2
        if (function_exists('finfo_open')) {
162 2
            $finfo = finfo_open(FILEINFO_MIME_TYPE);
163
            $result = finfo_buffer($finfo, $buffer);
164
            if (is_string($result)) {
0 ignored issues
show
introduced by
The condition is_string($result) is always true.
Loading history...
165
                return $result;
166
            }
167
        }
168
        return null;
169
    }
170
}
171