Passed
Push — master ( be59cf...adf0d1 )
by Arnaud
06:44
created

File::getRealPath()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3.0261

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 6
c 1
b 0
f 0
nc 3
nop 1
dl 0
loc 13
rs 10
ccs 6
cts 7
cp 0.8571
crap 3.0261
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of Cecil.
7
 *
8
 * Copyright (c) Arnaud Ligny <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
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
class File
21
{
22
    /** @var Filesystem */
23
    protected static $fs;
24
25
    /**
26
     * Returns a Symfony\Component\Filesystem instance.
27
     */
28 1
    public static function getFS(): Filesystem
29
    {
30 1
        if (!self::$fs instanceof Filesystem) {
31 1
            self::$fs = new Filesystem();
32
        }
33
34 1
        return self::$fs;
35
    }
36
37
    /**
38
     * file_get_contents() function with error handler.
39
     *
40
     * @return string|false
41
     */
42 1
    public static function fileGetContents(string $filename, ?string $userAgent = null)
43
    {
44 1
        if (empty($filename)) {
45
            return false;
46
        }
47
48 1
        set_error_handler(
49 1
            function ($severity, $message, $file, $line) {
50 1
                throw new \ErrorException($message, 0, $severity, $file, $line, null);
51 1
            }
52 1
        );
53
54
        try {
55 1
            $options = [
56 1
                'http' => [
57 1
                    'method'          => 'GET',
58 1
                    'follow_location' => true,
59 1
                ],
60 1
            ];
61 1
            if (!empty($userAgent)) {
62
                $options['http']['header'] = "User-Agent: $userAgent";
63
            }
64
65 1
            return file_get_contents($filename, false, stream_context_create($options));
66 1
        } catch (\ErrorException) {
67 1
            return false;
68
        } finally {
69 1
            restore_error_handler();
70
        }
71
    }
72
73
    /**
74
     * Returns the media type and subtype of a file.
75
     *
76
     * ie: ['text', 'text/plain']
77
     */
78 1
    public static function getMediaType(string $filename): array
79
    {
80
        try {
81 1
            if (false !== $subtype = mime_content_type($filename)) {
82 1
                return [explode('/', $subtype)[0], $subtype];
83
            }
84
            $mimeTypes = new MimeTypes();
85
            $subtype = $mimeTypes->guessMimeType($filename);
86
            if ($subtype === null) {
87
                throw new RuntimeException('Can\'t guess the media type.');
88
            }
89
90
            return [explode('/', $subtype)[0], $subtype];
91
        } catch (\Exception $e) {
92
            throw new RuntimeException(\sprintf('Can\'t get media type of "%s" (%s).', $filename, $e->getMessage()));
93
        }
94
    }
95
96
    /**
97
     * Returns the extension of a file.
98
     */
99 1
    public static function getExtension(string $filename): string
100
    {
101
        try {
102 1
            $ext = pathinfo($filename, PATHINFO_EXTENSION);
103 1
            if (!empty($ext)) {
104 1
                return $ext;
105
            }
106
            // guess the extension
107 1
            $mimeTypes = new MimeTypes();
108 1
            $mimeType = $mimeTypes->guessMimeType($filename);
109 1
            if ($mimeType === null) {
110
                throw new RuntimeException('Can\'t guess the media type.');
111
            }
112 1
            $exts = $mimeTypes->getExtensions($mimeType);
113
114 1
            return $exts[0];
115
        } catch (\Exception $e) {
116
            throw new RuntimeException(
117
                \sprintf('Can\'t get extension of "%s".', $filename),
118
                previous: $e,
119
            );
120
        }
121
    }
122
123
    /**
124
     * exif_read_data() function with error handler.
125
     */
126 1
    public static function readExif(string $filename): array
127
    {
128 1
        if (empty($filename)) {
129
            return [];
130
        }
131
132 1
        set_error_handler(
133 1
            function ($severity, $message, $file, $line) {
134
                throw new \ErrorException($message, 0, $severity, $file, $line, null);
135 1
            }
136 1
        );
137
138
        try {
139 1
            if (!\function_exists('exif_read_data')) {
140
                throw new \ErrorException('`exif` extension is not available.');
141
            }
142 1
            $exif = exif_read_data($filename, null, true);
143 1
            if ($exif === false) {
144
                return [];
145
            }
146
147 1
            return $exif;
148
        } catch (\ErrorException) {
149
            return [];
150
        } finally {
151 1
            restore_error_handler();
152
        }
153
    }
154
155
    /**
156
     * Returns the real path of a relative file path.
157
     */
158 1
    public static function getRealPath(string $path): string
159
    {
160
        // if file exists
161 1
        $filePath = realpath(\Cecil\Util::joinFile(__DIR__, '/../', $path));
162 1
        if ($filePath !== false) {
163 1
            return $filePath;
164
        }
165
        // if Phar
166 1
        if (Platform::isPhar()) {
167
            return \Cecil\Util::joinPath(Platform::getPharPath(), str_replace('../', '/', $path));
168
        }
169
170 1
        throw new RuntimeException(\sprintf('Can\'t get the real path of file "%s".', $path));
171
    }
172
173
    /**
174
     * Tests if a file path is remote.
175
     */
176 1
    public static function isRemote(string $path): bool
177
    {
178 1
        return (bool) preg_match('~^(?:f|ht)tps?://~i', $path);
179
    }
180
181
    /**
182
     * Tests if a remote file exists.
183
     */
184 1
    public static function isRemoteExists(string $path): bool
185
    {
186 1
        if (self::isRemote($path)) {
187 1
            $handle = @fopen($path, 'r');
188 1
            if (!empty($http_response_header)) {
189 1
                if (400 < (int) explode(' ', $http_response_header[0])[1]) {
190 1
                    return false;
191
                }
192
            }
193 1
            if (\is_resource($handle)) {
194 1
                return true;
195
            }
196
        }
197
198
        return false;
199
    }
200
}
201