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

68publishers / image-storage / 15008625056

13 May 2025 11:20PM UTC coverage: 92.317% (-0.6%) from 92.954%
15008625056

push

github

tg666
Added dependency on package `psr/http-message`

1526 of 1653 relevant lines covered (92.32%)

0.92 hits per line

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

61.46
/src/Resource/ResourceFactory.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace SixtyEightPublishers\ImageStorage\Resource;
6

7
use Intervention\Image\Exception\ImageException;
8
use Intervention\Image\Image;
9
use Intervention\Image\ImageManager;
10
use League\Flysystem\FilesystemException as LeagueFilesystemException;
11
use League\Flysystem\FilesystemReader;
12
use League\Flysystem\UnableToReadFile;
13
use Psr\Http\Message\StreamInterface;
14
use RuntimeException;
15
use SixtyEightPublishers\FileStorage\Exception\FileNotFoundException;
16
use SixtyEightPublishers\FileStorage\Exception\FilesystemException;
17
use SixtyEightPublishers\FileStorage\PathInfoInterface;
18
use SixtyEightPublishers\FileStorage\Resource\ResourceFactoryInterface;
19
use SixtyEightPublishers\FileStorage\Resource\ResourceInterface;
20
use SixtyEightPublishers\ImageStorage\Modifier\Facade\ModifierFacadeInterface;
21
use SixtyEightPublishers\ImageStorage\PathInfoInterface as ImagePathInfoInterface;
22
use SixtyEightPublishers\ImageStorage\Persistence\ImagePersisterInterface;
23
use function error_clear_last;
24
use function error_get_last;
25
use function fclose;
26
use function file_put_contents;
27
use function filter_var;
28
use function fopen;
29
use function fwrite;
30
use function get_debug_type;
31
use function is_file;
32
use function is_string;
33
use function sprintf;
34
use function stream_context_create;
35
use function sys_get_temp_dir;
36
use function tempnam;
37

38
final class ResourceFactory implements ResourceFactoryInterface
39
{
40
    public function __construct(
1✔
41
        private readonly FilesystemReader $filesystemReader,
42
        private readonly ImageManager $imageManager,
43
        private readonly ModifierFacadeInterface $modifierFacade,
44
    ) {}
1✔
45

46
    /**
47
     * @throws FileNotFoundException
48
     * @throws LeagueFilesystemException
49
     * @throws FilesystemException
50
     */
51
    public function createResource(PathInfoInterface $pathInfo): ResourceInterface
1✔
52
    {
53
        if ($pathInfo instanceof ImagePathInfoInterface && null !== $pathInfo->getModifiers()) {
1✔
54
            $sourcePathInfo = $pathInfo->withModifiers(null);
1✔
55
        }
56

57
        $path = isset($sourcePathInfo) ? $sourcePathInfo->getPath() : $pathInfo->getPath();
1✔
58
        $filesystemPath = ImagePersisterInterface::FILESYSTEM_PREFIX_SOURCE . $path;
1✔
59

60
        if (false === $this->filesystemReader->fileExists($filesystemPath)) {
1✔
61
            throw new FileNotFoundException($path);
1✔
62
        }
63

64
        try {
65
            $source = $this->filesystemReader->readStream($filesystemPath);
1✔
66
        } catch (UnableToReadFile $e) {
1✔
67
            throw new FilesystemException(sprintf(
1✔
68
                'Unable to read file "%s".',
1✔
69
                $path,
1✔
70
            ), 0, $e);
1✔
71
        } catch (LeagueFilesystemException $e) {
1✔
72
            throw new FilesystemException($e->getMessage(), 0, $e);
1✔
73
        }
74

75
        return $this->createTmpFileResource(
1✔
76
            pathInfo: $pathInfo,
1✔
77
            location: $path,
78
            source: $source,
79
        );
80
    }
81

82
    public function createResourceFromFile(PathInfoInterface $pathInfo, string $filename): ResourceInterface
1✔
83
    {
84
        if (!filter_var($filename, FILTER_VALIDATE_URL)) {
1✔
85
            return new ImageResource(
1✔
86
                pathInfo: $pathInfo,
1✔
87
                image: $this->makeImage(
1✔
88
                    source: $filename,
1✔
89
                    location: $filename,
90
                ),
91
                localFilename: $filename,
92
                modifierFacade: $this->modifierFacade,
1✔
93
            );
94
        }
95

96
        error_clear_last();
×
97

98
        $context = stream_context_create(
×
99
            options: [
100
                'http' => [
101
                    'method' => 'GET',
×
102
                    'protocol_version' => 1.1,
103
                    'header' => "Accept-language: en\r\n" . "User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36\r\n",
104
                ],
105
            ],
106
        );
107

108
        $source = @fopen(
×
109
            filename: $filename,
×
110
            mode: 'rb',
×
111
            context: $context,
×
112
        );
113

114
        if (false === $source) {
×
115
            throw new FilesystemException(
×
116
                message: sprintf(
×
117
                    'Can not read stream from url "%s". %s',
×
118
                    $filename,
×
119
                    error_get_last()['message'] ?? '',
×
120
                ),
121
            );
122
        }
123

124
        return $this->createTmpFileResource(
×
125
            pathInfo: $pathInfo,
×
126
            location: $filename,
127
            source: $source,
128
        );
129
    }
130

131
    public function createResourceFromPsrStream(PathInfoInterface $pathInfo, StreamInterface $stream): ResourceInterface
1✔
132
    {
133
        if ($stream->isSeekable()) {
1✔
134
            try {
135
                $stream->rewind();
1✔
136
            } catch (RuntimeException $e) {
×
137
                # ignore
138
            }
139
        }
140

141
        $uri = $stream->getMetadata('uri');
1✔
142

143
        if (is_string($uri) && @is_file($uri)) {
1✔
144
            return new ImageResource(
1✔
145
                pathInfo: $pathInfo,
1✔
146
                image: $this->makeImage(
1✔
147
                    source: $stream,
1✔
148
                    location: $uri,
149
                ),
150
                localFilename: $uri,
151
                modifierFacade: $this->modifierFacade,
1✔
152
            );
153
        }
154

155
        return $this->createTmpFileResource(
1✔
156
            pathInfo: $pathInfo,
1✔
157
            location: get_debug_type($stream),
1✔
158
            source: $stream,
159
        );
160
    }
161

162
    /**
163
     * @throws FilesystemException
164
     */
165
    private function createTmpFileResource(PathInfoInterface $pathInfo, string $location, mixed $source): TmpFileImageResource
1✔
166
    {
167
        $tmpFilename = (string) tempnam(sys_get_temp_dir(), '68Publishers_ImageStorage');
1✔
168

169
        if ($source instanceof StreamInterface) {
1✔
170
            $tmpStream = @fopen($tmpFilename, 'wb');
1✔
171

172
            if (false === $tmpStream) {
1✔
173
                throw new FilesystemException(
×
174
                    message: sprintf(
×
175
                        'Unable to open tmp file "%s" for writing.',
×
176
                        $tmpFilename,
×
177
                    ),
178
                );
179
            }
180

181
            try {
182
                while (!$source->eof()) {
1✔
183
                    $chunk = $source->read(8192);
1✔
184

185
                    if ('' === $chunk) {
1✔
186
                        break;
×
187
                    }
188

189
                    fwrite($tmpStream, $chunk);
1✔
190
                }
191
            } catch (RuntimeException $e) {
×
192
                throw new FilesystemException(
×
193
                    message: sprintf(
×
194
                        'Unable to write tmp file for "%s". %s',
×
195
                        $location,
×
196
                        $e->getMessage(),
×
197
                    ),
198
                    previous: $e,
199
                );
200
            } finally {
1✔
201
                fclose($tmpStream);
1✔
202
            }
203
        } elseif (false === file_put_contents($tmpFilename, $source)) {
1✔
204
            throw new FilesystemException(
×
205
                message: sprintf(
×
206
                    'Unable to write tmp file for "%s".',
×
207
                    $location,
×
208
                ),
209
            );
210
        }
211

212
        return new TmpFileImageResource(
1✔
213
            pathInfo: $pathInfo,
1✔
214
            image: $this->makeImage(
1✔
215
                source: $tmpFilename,
1✔
216
                location: $location,
217
            ),
218
            modifierFacade: $this->modifierFacade,
1✔
219
            tmpFile: new TmpFile($tmpFilename),
1✔
220
        );
221
    }
222

223
    /**
224
     * @throws FilesystemException
225
     */
226
    private function makeImage(mixed $source, string $location): Image
1✔
227
    {
228
        try {
229
            return $this->imageManager->make($source);
1✔
230
        } catch (ImageException $e) {
×
231
            throw new FilesystemException(
×
232
                message: sprintf(
×
233
                    'Unable to create image "%s". %s',
×
234
                    $location,
×
235
                    $e->getMessage(),
×
236
                ),
237
                previous: $e,
238
            );
239
        }
240
    }
241
}
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

© 2025 Coveralls, Inc