Passed
Push — master ( f53a08...25958f )
by Aleksei
01:47
created

FileBucket::setContentType()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 1 Features 1
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
c 1
b 1
f 1
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 35
    public function __construct($data, string $contentType = null, string $fileName = null)
29
    {
30
        switch (true) {
31 35
            case $data instanceof SplFileInfo:
32 3
                $fileName = $fileName ?? $data->getFilename();
33 3
                $contentType = $contentType ?? $this->fileContentType($data->getPathname());
34 3
                parent::__construct($data);
35 3
                break;
36 32
            case is_string($data):
37 2
            case is_resource($data):
38 31
                parent::__construct($data);
39 31
                break;
40
            default:
41 1
                throw new InvalidArgumentException(
42 1
                    'The $data parameter must be a resource, a string or an instance of SplFileInfo.'
43
                );
44
        }
45
46 34
        if ($contentType !== null) {
47 3
            $this->setContentType($contentType);
48
        }
49 34
        if ($fileName !== null) {
50 4
            $this->setAttachment($fileName);
51
        }
52 34
    }
53
54 2
    public static function createFromPath(string $filePath, string $contentType = null, string $fileName = null): self
55
    {
56 2
        return new static(new SplFileInfo($filePath), $contentType, $fileName);
57
    }
58
59 11
    public function getContentType(): ?string
60
    {
61 11
        return $this->contentType;
62
    }
63 10
    public function getFileName(): ?string
64
    {
65 10
        return $this->fileName;
66
    }
67 3
    public function hasDisposition(): bool
68
    {
69 3
        return $this->contentDisposition !== null;
70
    }
71 6
    public function isAttachment(): bool
72
    {
73 6
        return $this->contentDisposition === self::DISPOSITION_ATTACHMENT;
74
    }
75 4
    public function isInline(): bool
76
    {
77 4
        return $this->contentDisposition === self::DISPOSITION_INLINE;
78
    }
79
80 14
    public function withAttachment(string $filename = null): self
81
    {
82 14
        $clone = clone $this;
83 14
        $clone->setAttachment($filename);
84 14
        return $clone;
85
    }
86 3
    public function withContentType(?string $contentType): self
87
    {
88 3
        $clone = clone $this;
89 3
        $clone->setContentType($contentType);
90 3
        return $clone;
91
    }
92 4
    public function withInline(): self
93
    {
94 4
        $clone = clone $this;
95 4
        $clone->setInline();
96 4
        return $clone;
97
    }
98
99 6
    protected function setContentType(?string $contentType): void
100
    {
101 6
        $this->contentType = $contentType;
102 6
        $this->setHeader(Header::CONTENT_TYPE, $contentType);
103 6
    }
104 4
    protected function setInline(): void
105
    {
106 4
        $this->contentDisposition = self::DISPOSITION_INLINE;
107 4
        $this->setDispositionHeader();
108 4
    }
109 18
    final protected function setAttachment(?string $fileName): void
110
    {
111 18
        $this->contentDisposition = self::DISPOSITION_ATTACHMENT;
112 18
        $this->fileName = $fileName;
113 18
        $this->setDispositionHeader();
114 18
    }
115 20
    final protected function setDispositionHeader(): void
116
    {
117 20
        $headerBody = ($this->contentDisposition === self::DISPOSITION_ATTACHMENT && $this->fileName !== null)
118 14
            ? sprintf(
119 14
                '%s; filename="%s"; filename*=UTF-8\'\'%s',
120 14
                $this->contentDisposition,
121 14
                preg_replace('/[\x00-\x1F\x7F\"]/', ' ', $this->fileName),
122 14
                rawurlencode($this->fileName)
123
            )
124 20
            : $this->contentDisposition;
125 20
        $this->setHeader(Header::CONTENT_DISPOSITION, $headerBody);
126 20
    }
127 2
    private function fileContentType(?string $filePath): ?string
128
    {
129 2
        if ($filePath === null || !is_file($filePath) || !is_readable($filePath)) {
130 1
            return null;
131
        }
132 1
        $result = null;
133
        try {
134 1
            if (function_exists('finfo_open')) {
135 1
                $finfo = finfo_open(FILEINFO_MIME_TYPE);
136 1
                $result = finfo_file($finfo, $filePath);
137 1
                if (is_string($result)) {
138 1
                    return $result;
139
                }
140
            }
141
            $result = $result ?? (function_exists('mime_content_type') ? mime_content_type($filePath) : null);
142
            return is_string($result) ? $result : null;
143
        } catch (\Throwable $e) {
144
            return null;
145
        }
146
    }
147
}
148