• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Cecilapp / Cecil / 20286890396

17 Dec 2025 12:06AM UTC coverage: 82.531% (-0.008%) from 82.539%
20286890396

push

github

ArnaudLigny
Fix image height attribute handling in html()

Refactors the logic for setting image width and height attributes to only set them if not already present in the attributes array. This prevents overwriting explicitly provided values and ensures correct attribute assignment.

2 of 2 new or added lines in 1 file covered. (100.0%)

1 existing line in 1 file now uncovered.

3307 of 4007 relevant lines covered (82.53%)

0.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

69.74
/src/Util/File.php
1
<?php
2

3
/**
4
 * This file is part of Cecil.
5
 *
6
 * (c) Arnaud Ligny <arnaud@ligny.fr>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11

12
declare(strict_types=1);
13

14
namespace Cecil\Util;
15

16
use Cecil\Exception\RuntimeException;
17
use Symfony\Component\Filesystem\Filesystem;
18
use Symfony\Component\Mime\MimeTypes;
19

20
/**
21
 * File utility class.
22
 *
23
 * This class provides various utility methods for file handling,
24
 * including reading file contents, getting media types and extensions,
25
 * reading EXIF data, and checking if files are remote.
26
 */
27
class File
28
{
29
    /** @var Filesystem */
30
    protected static $fs;
31

32
    /**
33
     * Returns a Symfony\Component\Filesystem instance.
34
     */
35
    public static function getFS(): Filesystem
36
    {
37
        if (!self::$fs instanceof Filesystem) {
1✔
38
            self::$fs = new Filesystem();
1✔
39
        }
40

41
        return self::$fs;
1✔
42
    }
43

44
    /**
45
     * file_get_contents() function with error handler.
46
     */
47
    public static function fileGetContents(string $filename, ?string $userAgent = null): string|false
48
    {
49
        if (empty($filename)) {
1✔
50
            return false;
×
51
        }
52

53
        set_error_handler(
1✔
54
            function ($severity, $message, $file, $line) {
1✔
55
                throw new \ErrorException($message, 0, $severity, $file, $line, null);
1✔
56
            }
1✔
57
        );
1✔
58

59
        try {
60
            $options = [
1✔
61
                'http' => [
1✔
62
                    'method'          => 'GET',
1✔
63
                    'follow_location' => true,
1✔
64
                ],
1✔
65
            ];
1✔
66
            if (!empty($userAgent)) {
1✔
67
                $options['http']['header'] = "User-Agent: $userAgent";
×
68
            }
69

70
            return file_get_contents($filename, false, stream_context_create($options));
1✔
71
        } catch (\ErrorException) {
1✔
72
            return false;
1✔
73
        } finally {
74
            restore_error_handler();
1✔
75
        }
76
    }
77

78
    /**
79
     * Returns the media type and subtype of a file.
80
     *
81
     * ie: ['text', 'text/plain']
82
     */
83
    public static function getMediaType(string $filename): array
84
    {
85
        try {
86
            if (false !== $subtype = mime_content_type($filename)) {
1✔
87
                return [explode('/', $subtype)[0], $subtype];
1✔
88
            }
89
            $mimeTypes = new MimeTypes();
×
90
            $subtype = $mimeTypes->guessMimeType($filename);
×
91
            if ($subtype === null) {
×
92
                throw new RuntimeException('Unable to guess the media type.');
×
93
            }
94

95
            return [explode('/', $subtype)[0], $subtype];
×
96
        } catch (\Exception $e) {
×
97
            throw new RuntimeException(\sprintf('Unable to get media type of "%s" (%s).', $filename, $e->getMessage()));
×
98
        }
99
    }
100

101
    /**
102
     * Returns the extension of a file.
103
     */
104
    public static function getExtension(string $filename): string
105
    {
106
        try {
107
            $ext = pathinfo($filename, \PATHINFO_EXTENSION);
1✔
108
            if (!empty($ext)) {
1✔
109
                return $ext;
1✔
110
            }
111
            // guess the extension
112
            $mimeTypes = new MimeTypes();
1✔
113
            $mimeType = $mimeTypes->guessMimeType($filename);
1✔
114
            if ($mimeType === null) {
1✔
115
                throw new RuntimeException('Unable to guess the media type.');
×
116
            }
117
            $exts = $mimeTypes->getExtensions($mimeType);
1✔
118

119
            return $exts[0];
1✔
120
        } catch (\Exception $e) {
×
121
            throw new RuntimeException(
×
122
                \sprintf('Unable to get extension of "%s".', $filename),
×
123
                previous: $e,
×
124
            );
×
125
        }
126
    }
127

128
    /**
129
     * exif_read_data() function with error handler.
130
     */
131
    public static function readExif(string $filename): array
132
    {
133
        if (empty($filename)) {
1✔
134
            return [];
×
135
        }
136

137
        set_error_handler(
1✔
138
            function ($severity, $message, $file, $line) {
1✔
139
                throw new \ErrorException($message, 0, $severity, $file, $line, null);
×
140
            }
1✔
141
        );
1✔
142

143
        try {
144
            if (!\function_exists('exif_read_data')) {
1✔
145
                throw new \ErrorException('`exif` extension is not available.');
×
146
            }
147
            $exif = exif_read_data($filename, null, true);
1✔
148
            if ($exif === false) {
1✔
149
                return [];
×
150
            }
151

152
            return $exif;
1✔
153
        } catch (\ErrorException) {
×
154
            return [];
×
155
        } finally {
156
            restore_error_handler();
1✔
157
        }
158
    }
159

160
    /**
161
     * Returns the real path of a relative file path.
162
     */
163
    public static function getRealPath(string $path): string
164
    {
165
        // if file exists
166
        $filePath = realpath(\Cecil\Util::joinFile(__DIR__, '/../', $path));
1✔
167
        if ($filePath !== false) {
1✔
168
            return $filePath;
1✔
169
        }
170
        // if Phar
171
        if (Platform::isPhar()) {
1✔
172
            return \Cecil\Util::joinPath(Platform::getPharPath(), str_replace('../', '/', $path));
×
173
        }
174

175
        throw new RuntimeException(\sprintf('Unable to get the real path of file "%s".', $path));
1✔
176
    }
177

178
    /**
179
     * Tests if a file path is remote.
180
     */
181
    public static function isRemote(string $path): bool
182
    {
183
        return (bool) preg_match('~^(?:f|ht)tps?://~i', $path);
1✔
184
    }
185

186
    /**
187
     * Tests if a remote file exists.
188
     */
189
    public static function isRemoteExists(string $path): bool
190
    {
191
        if (self::isRemote($path)) {
1✔
192
            $handle = @fopen($path, 'r');
1✔
193
            if (!empty($http_response_header)) {
1✔
194
                if (400 < (int) explode(' ', $http_response_header[0])[1]) {
1✔
195
                    return false;
1✔
196
                }
197
            }
198
            if (\is_resource($handle)) {
1✔
199
                return true;
1✔
200
            }
201
        }
202

UNCOV
203
        return false;
×
204
    }
205
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc