Failed Conditions
Pull Request — master (#4275)
by Owen
21:43 queued 04:18
created

Drawing::getMediaFilename()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 0
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Worksheet;
4
5
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
6
use ZipArchive;
7
8
class Drawing extends BaseDrawing
9
{
10
    const IMAGE_TYPES_CONVERTION_MAP = [
11
        IMAGETYPE_GIF => IMAGETYPE_PNG,
12
        IMAGETYPE_JPEG => IMAGETYPE_JPEG,
13
        IMAGETYPE_PNG => IMAGETYPE_PNG,
14
        IMAGETYPE_BMP => IMAGETYPE_PNG,
15
    ];
16
17
    /**
18
     * Path.
19
     */
20
    private string $path;
21
22
    /**
23
     * Whether or not we are dealing with a URL.
24
     */
25
    private bool $isUrl;
26
27
    /**
28
     * Create a new Drawing.
29
     */
30 194
    public function __construct()
31
    {
32
        // Initialise values
33 194
        $this->path = '';
34 194
        $this->isUrl = false;
35
36
        // Initialize parent
37 194
        parent::__construct();
38
    }
39
40
    /**
41
     * Get Filename.
42
     */
43 1
    public function getFilename(): string
44
    {
45 1
        return basename($this->path);
46
    }
47
48
    /**
49
     * Get indexed filename (using image index).
50
     */
51 45
    public function getIndexedFilename(): string
52
    {
53 45
        return md5($this->path) . '.' . $this->getExtension();
54
    }
55
56
    /**
57
     * Get Extension.
58
     */
59 45
    public function getExtension(): string
60
    {
61 45
        $exploded = explode('.', basename($this->path));
62
63 45
        return $exploded[count($exploded) - 1];
64
    }
65
66
    /**
67
     * Get full filepath to store drawing in zip archive.
68
     */
69 3
    public function getMediaFilename(): string
70
    {
71 3
        if (!array_key_exists($this->type, self::IMAGE_TYPES_CONVERTION_MAP)) {
72 1
            throw new PhpSpreadsheetException('Unsupported image type in comment background. Supported types: PNG, JPEG, BMP, GIF.');
73
        }
74
75 3
        return sprintf('image%d%s', $this->getImageIndex(), $this->getImageFileExtensionForSave());
76
    }
77
78
    /**
79
     * Get Path.
80
     */
81 117
    public function getPath(): string
82
    {
83 117
        return $this->path;
84
    }
85
86
    /**
87
     * Set Path.
88
     *
89
     * @param string $path File path
90
     * @param bool $verifyFile Verify file
91
     * @param ?ZipArchive $zip Zip archive instance
92
     *
93
     * @return $this
94
     */
95 104
    public function setPath(string $path, bool $verifyFile = true, ?ZipArchive $zip = null): static
96
    {
97 104
        $this->isUrl = false;
98 104
        if (preg_match('~^data:image/[a-z]+;base64,~', $path) === 1) {
99 4
            $this->path = $path;
100
101 4
            return $this;
102
        }
103
104 102
        $this->path = '';
105
        // Check if a URL has been passed. https://stackoverflow.com/a/2058596/1252979
106 102
        if (filter_var($path, FILTER_VALIDATE_URL)) {
107 3
            if (!preg_match('/^(http|https|file|ftp|s3):/', $path)) {
108 2
                throw new PhpSpreadsheetException('Invalid protocol for linked drawing');
109
            }
110
            // Implicit that it is a URL, rather store info than running check above on value in other places.
111 1
            $this->isUrl = true;
112 1
            $ctx = null;
113
            // https://github.com/php/php-src/issues/16023
114
            // experiment with stream context
115 1
            if (str_starts_with($path, 'https:')) {
116 1
                $ctx = stream_context_create([
117 1
                    'ssl' => ['crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT],
118 1
                    'http' => [
119 1
                        'user_agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
120 1
                        'Connection: keep-alive',
121 1
                        'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
122 1
                    ],
123 1
                ]);
124
            }
125 1
            $imageContents = @file_get_contents($path, false, $ctx);
126 1
            if ($imageContents !== false) {
127 1
                $filePath = tempnam(sys_get_temp_dir(), 'Drawing');
128 1
                if ($filePath) {
129 1
                    $put = @file_put_contents($filePath, $imageContents);
130 1
                    if ($put !== false) {
131 1
                        if ($this->isImage($filePath)) {
132 1
                            $this->path = $path;
133 1
                            $this->setSizesAndType($filePath);
134
                        }
135 1
                        unlink($filePath);
136
                    }
137
                }
138
            }
139 99
        } elseif ($zip instanceof ZipArchive) {
140 62
            $zipPath = explode('#', $path)[1];
141 62
            $locate = @$zip->locateName($zipPath);
142 62
            if ($locate !== false) {
143 62
                if ($this->isImage($path)) {
144 62
                    $this->path = $path;
145 62
                    $this->setSizesAndType($path);
146
                }
147
            }
148
        } else {
149 51
            $exists = @file_exists($path);
150 51
            if ($exists !== false && $this->isImage($path)) {
151 49
                $this->path = $path;
152 49
                $this->setSizesAndType($path);
153
            }
154
        }
155 100
        if ($this->path === '' && $verifyFile) {
156 1
            throw new PhpSpreadsheetException("File $path not found!");
157
        }
158
159 99
        if ($this->worksheet !== null) {
160 2
            if ($this->path !== '') {
161 2
                $this->worksheet->getCell($this->coordinates);
162
            }
163
        }
164
165 99
        return $this;
166
    }
167
168 98
    private function isImage(string $path): bool
169
    {
170 98
        $mime = (string) @mime_content_type($path);
171 98
        $retVal = false;
172 98
        if (str_starts_with($mime, 'image/')) {
173 97
            $retVal = true;
174 3
        } elseif ($mime === 'application/octet-stream') {
175 2
            $extension = pathinfo($path, PATHINFO_EXTENSION);
176 2
            $retVal = in_array($extension, ['bin', 'emf'], true);
177
        }
178
179 98
        return $retVal;
180
    }
181
182
    /**
183
     * Get isURL.
184
     */
185 43
    public function getIsURL(): bool
186
    {
187 43
        return $this->isUrl;
188
    }
189
190
    /**
191
     * Set isURL.
192
     *
193
     * @return $this
194
     */
195
    public function setIsURL(bool $isUrl): self
196
    {
197
        $this->isUrl = $isUrl;
198
199
        return $this;
200
    }
201
202
    /**
203
     * Get hash code.
204
     *
205
     * @return string Hash code
206
     */
207 43
    public function getHashCode(): string
208
    {
209 43
        return md5(
210 43
            $this->path
211 43
            . parent::getHashCode()
212 43
            . __CLASS__
213 43
        );
214
    }
215
216
    /**
217
     * Get Image Type for Save.
218
     */
219 1
    public function getImageTypeForSave(): int
220
    {
221 1
        if (!array_key_exists($this->type, self::IMAGE_TYPES_CONVERTION_MAP)) {
222 1
            throw new PhpSpreadsheetException('Unsupported image type in comment background. Supported types: PNG, JPEG, BMP, GIF.');
223
        }
224
225 1
        return self::IMAGE_TYPES_CONVERTION_MAP[$this->type];
226
    }
227
228
    /**
229
     * Get Image file extention for Save.
230
     */
231 3
    public function getImageFileExtensionForSave(bool $includeDot = true): string
232
    {
233 3
        if (!array_key_exists($this->type, self::IMAGE_TYPES_CONVERTION_MAP)) {
234 1
            throw new PhpSpreadsheetException('Unsupported image type in comment background. Supported types: PNG, JPEG, BMP, GIF.');
235
        }
236
237 3
        $result = image_type_to_extension(self::IMAGE_TYPES_CONVERTION_MAP[$this->type], $includeDot);
238
239 3
        return "$result";
240
    }
241
242
    /**
243
     * Get Image mime type.
244
     */
245 3
    public function getImageMimeType(): string
246
    {
247 3
        if (!array_key_exists($this->type, self::IMAGE_TYPES_CONVERTION_MAP)) {
248 1
            throw new PhpSpreadsheetException('Unsupported image type in comment background. Supported types: PNG, JPEG, BMP, GIF.');
249
        }
250
251 3
        return image_type_to_mime_type(self::IMAGE_TYPES_CONVERTION_MAP[$this->type]);
252
    }
253
}
254