Passed
Push — master ( 0ad23c...4c970b )
by Amin
03:26
created

Export::tmpDirectory()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 1
dl 0
loc 10
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * This file is part of the PHP-FFmpeg-video-streaming package.
5
 *
6
 * (c) Amin Yazdanpanah <[email protected]>
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
namespace Streaming;
13
14
use FFMpeg\Exception\ExceptionInterface;
15
use Streaming\Clouds\AWS;
16
use Streaming\Clouds\Cloud;
17
use Streaming\Clouds\CloudManager;
18
use Streaming\Clouds\GoogleCloudStorage;
19
use Streaming\Clouds\MicrosoftAzure;
20
use Streaming\Exception\Exception;
21
use Streaming\Exception\InvalidArgumentException;
22
use Streaming\Exception\RuntimeException;
23
use Streaming\Filters\Filter;
24
use Streaming\Traits\Formats;
25
26
abstract class Export
27
{
28
    use Formats;
29
30
    /** @var object */
31
    protected $media;
32
33
    /** @var array */
34
    protected $path_info;
35
36
    /** @var string */
37
    protected $strict = "-2";
38
39
    /** @var string */
40
    protected $tmp_dir;
41
42
    /**
43
     * Export constructor.
44
     * @param Media $media
45
     */
46
    public function __construct(Media $media)
47
    {
48
        $this->media = $media;
49
        $this->path_info = pathinfo($media->getPath());
50
    }
51
52
    /**
53
     * @param string $path
54
     * @param array $clouds
55
     * @param bool $metadata
56
     * @return mixed
57
     * @throws Exception
58
     */
59
    public function save(string $path = null, array $clouds = [], bool $metadata = true)
60
    {
61
        /**
62
         * Synopsis
63
         * ------------------------------------------------------------------------------
64
         * 1. Create directory path, path info array, and temporary folders(if it is required).
65
         * 2. Build object and run FFmpeg to package media content and save on the local machine.
66
         * 3. If the cloud is specified, entire packaged files will be uploaded to clouds.
67
         * 4. If files were saved into a tmp folder, then they will be moved to the local path(if the path is specified).
68
         * 5. Return all video and also streams' metadata and save as a json file on the local machine(it won't save metadata to clouds because of some security concerns).
69
         * 6. In the end, clear all tmp files.
70
         * ------------------------------------------------------------------------------
71
         */
72
73
        $this->createPathInfoAndTmpDir($path, $clouds);
74
        $this->runFFmpeg();
75
        CloudManager::saveToClouds($clouds, $this->tmp_dir);
76
        $this->moveTmpFolder($path);
77
78
        return $metadata ? (new Metadata($this))->extract() : $this;
79
    }
80
81
    /**
82
     * @param $path
83
     * @param $clouds
84
     * @throws Exception
85
     */
86
    private function createPathInfoAndTmpDir($path, $clouds): void
87
    {
88
        if (null !== $path) {
89
            $this->path_info = pathinfo($path);
90
            FileManager::makeDir($this->path_info["dirname"]);
91
        }
92
93
        if ($clouds) {
94
            $this->tmpDirectory($path);
95
        }
96
97
        if (null === $path && $this->media->isTmp() && !$clouds) {
98
            throw new InvalidArgumentException("You need to specify a path. It is not possible to save to a tmp directory");
99
        }
100
    }
101
102
    /**
103
     * @param $path
104
     * @throws Exception
105
     */
106
    private function tmpDirectory($path)
107
    {
108
        if (null !== $path) {
109
            $basename = pathinfo($path, PATHINFO_BASENAME);
110
        } else {
111
            $basename = Helper::randomString();
112
        }
113
114
        $this->tmp_dir = FileManager::tmpDir();
115
        $this->path_info = pathinfo($this->tmp_dir . $basename);
116
    }
117
118
    /**
119
     * Run FFmpeg to package media content
120
     */
121
    private function runFFmpeg(): void
122
    {
123
        try {
124
            $this->media
125
                ->addFilter($this->getFilter())
126
                ->save($this->getFormat(), $this->getPath());
127
        } catch (ExceptionInterface $e) {
128
            throw new RuntimeException(sprintf("There was an error saving files: \n\n reason: \n %s", $e->getMessage()),
129
                $e->getCode(),
130
                $e
131
            );
132
        }
133
    }
134
135
    /**
136
     * @return Filter
137
     */
138
    abstract protected function getFilter(): Filter;
139
140
    /**
141
     * @return string
142
     */
143
    private function getPath(): string
144
    {
145
        $dirname = str_replace("\\", "/", $this->path_info["dirname"]);
146
        $filename = substr($this->path_info["filename"], -100);
147
        $path = '';
148
149
        if ($this instanceof DASH) {
150
            $path = $dirname . "/" . $filename . ".mpd";
151
        } elseif ($this instanceof HLS) {
152
            $representations = $this->getRepresentations();
153
            $path = $dirname . "/" . $filename . "_" . end($representations)->getHeight() . "p.m3u8";
154
            ExportHLSPlaylist::savePlayList($dirname . DIRECTORY_SEPARATOR . $filename . ".m3u8", $this->getRepresentations(), $filename);
155
        }
156
157
        return $path;
158
    }
159
160
    /**
161
     * @param string|null $path
162
     * @throws Exception
163
     */
164
    private function moveTmpFolder(?string $path)
165
    {
166
        if ($this->tmp_dir && $path) {
167
            FileManager::moveDir($this->tmp_dir, pathinfo($path, PATHINFO_DIRNAME) . DIRECTORY_SEPARATOR);
168
            $this->path_info = pathinfo($path);
169
        }
170
    }
171
172
    /**
173
     * @return array
174
     */
175
    public function getPathInfo(): array
176
    {
177
        return $this->path_info;
178
    }
179
180
    /**
181
     * @return object|Media
182
     */
183
    public function getMedia(): Media
184
    {
185
        return $this->media;
186
    }
187
188
    /**
189
     * @param string $strict
190
     * @return Export
191
     */
192
    public function setStrict(string $strict): Export
193
    {
194
        $this->strict = $strict;
195
        return $this;
196
    }
197
198
    /**
199
     * @return string
200
     */
201
    public function getStrict(): string
202
    {
203
        return $this->strict;
204
    }
205
206
    /**
207
     * clear tmp files
208
     */
209
    public function __destruct()
210
    {
211
        sleep(1);
212
213
        if ($this->media->isTmp()) {
214
            @unlink($this->media->getPath());
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

214
            /** @scrutinizer ignore-unhandled */ @unlink($this->media->getPath());

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
215
        }
216
217
        if ($this->tmp_dir) {
218
            FileManager::deleteDirectory($this->tmp_dir);
219
        }
220
221
        if ($this instanceof HLS && $this->tmp_key_info_file) {
222
            @unlink($this->getHlsKeyInfoFile());
223
        }
224
    }
225
226
    /**
227
     * @param string $url
228
     * @param string $name
229
     * @param string|null $path
230
     * @param string $method
231
     * @param array $headers
232
     * @param array $options
233
     * @return mixed
234
     * @throws Exception
235
     * @deprecated this method is deprecated
236
     */
237
    // @TODO: should be removed in the next releases.
238
    public function saveToCloud(
239
        string $url,
240
        string $name,
241
        string $path = null,
242
        string $method = 'GET',
243
        array $headers = [],
244
        array $options = []
245
    )
246
    {
247
        @trigger_error('saveToCloud method is deprecated and will be removed in a future release. Use Cloud instead', E_USER_DEPRECATED);
248
        if ($this instanceof HLS && $this->getTsSubDirectory()) {
249
            throw new InvalidArgumentException("It is not possible to create subdirectory in a cloud");
250
        }
251
        $results = $this->saveToTemporaryFolder($path);
0 ignored issues
show
Deprecated Code introduced by
The function Streaming\Export::saveToTemporaryFolder() has been deprecated: this method is deprecated ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

251
        $results = /** @scrutinizer ignore-deprecated */ $this->saveToTemporaryFolder($path);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
252
        sleep(1);
253
254
        $cloud = new Cloud($url, $method, $options);
255
        $cloud->uploadDirectory($this->tmp_dir, ['name' => $name, 'headers' => $headers]);
256
257
        $this->moveTmpFolder($path);
258
259
        return $results;
260
    }
261
262
    /**
263
     * @param array $config
264
     * @param string $dest
265
     * @param string|null $path
266
     * @return mixed
267
     * @throws Exception
268
     * @deprecated this method is deprecated
269
     */
270
    // @TODO: should be removed in the next releases.
271
    public function saveToS3(
272
        array $config,
273
        string $dest,
274
        string $path = null
275
    )
276
    {
277
        @trigger_error('saveToS3 method is deprecated and will be removed in a future release. Use AWS instead', E_USER_DEPRECATED);
278
        $results = $this->saveToTemporaryFolder($path);
0 ignored issues
show
Deprecated Code introduced by
The function Streaming\Export::saveToTemporaryFolder() has been deprecated: this method is deprecated ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

278
        $results = /** @scrutinizer ignore-deprecated */ $this->saveToTemporaryFolder($path);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
279
        sleep(1);
280
281
        $aws = new AWS($config);
282
        $aws->uploadDirectory($this->tmp_dir, ['dest' => $dest]);
283
284
        $this->moveTmpFolder($path);
285
286
        return $results;
287
    }
288
289
    /**
290
     * @param array $config
291
     * @param string $bucket
292
     * @param string|null $path
293
     * @param array $options
294
     * @param bool $userProject
295
     * @return mixed
296
     * @throws Exception
297
     * @deprecated this method is deprecated
298
     */
299
    // @TODO: should be removed in the next releases.
300
    public function saveToGCS(
301
        array $config,
302
        string $bucket,
303
        string $path = null,
304
        array $options = [],
305
        bool $userProject = false
306
    )
307
    {
308
        @trigger_error('saveToGCS method is deprecated and will be removed in a future release. Use GoogleCloudStorage instead', E_USER_DEPRECATED);
309
        if ($this instanceof HLS && $this->getTsSubDirectory()) {
310
            throw new InvalidArgumentException("It is not possible to create subdirectory in a cloud");
311
        }
312
313
        $results = $this->saveToTemporaryFolder($path);
0 ignored issues
show
Deprecated Code introduced by
The function Streaming\Export::saveToTemporaryFolder() has been deprecated: this method is deprecated ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

313
        $results = /** @scrutinizer ignore-deprecated */ $this->saveToTemporaryFolder($path);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
314
        sleep(1);
315
316
        $google_cloud = new GoogleCloudStorage($config, $bucket, $userProject);
317
        $google_cloud->uploadDirectory($this->tmp_dir, $options);
318
319
        $this->moveTmpFolder($path);
320
321
        return $results;
322
    }
323
324
    /**
325
     * @param string $connectionString
326
     * @param string $container
327
     * @param string|null $path
328
     * @return mixed
329
     * @throws Exception
330
     * @deprecated this method is deprecated
331
     */
332
    // @TODO: should be removed in the next releases.
333
    public function saveToMAS(
334
        string $connectionString,
335
        string $container,
336
        string $path = null
337
    )
338
    {
339
        @trigger_error('saveToMAS method is deprecated and will be removed in a future release. Use MicrosoftAzure instead', E_USER_DEPRECATED);
340
341
        if ($this instanceof HLS && $this->getTsSubDirectory()) {
342
            throw new InvalidArgumentException("It is not possible to create subdirectory in a cloud");
343
        }
344
345
        $results = $this->saveToTemporaryFolder($path);
0 ignored issues
show
Deprecated Code introduced by
The function Streaming\Export::saveToTemporaryFolder() has been deprecated: this method is deprecated ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

345
        $results = /** @scrutinizer ignore-deprecated */ $this->saveToTemporaryFolder($path);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
346
        sleep(1);
347
348
        $google_cloud = new MicrosoftAzure($connectionString);
349
        $google_cloud->uploadDirectory($this->tmp_dir, ['container' => $container]);
350
351
        $this->moveTmpFolder($path);
352
353
        return $results;
354
    }
355
356
    /**
357
     * @param $path
358
     * @return array
359
     * @throws Exception
360
     * @deprecated this method is deprecated
361
     */
362
    // @TODO: should be removed in the next releases.
363
    private function saveToTemporaryFolder($path)
364
    {
365
        $basename = Helper::randomString();
366
367
        if (null !== $path) {
368
            $basename = pathinfo($path, PATHINFO_BASENAME);
369
        }
370
371
        $this->tmp_dir = FileManager::tmpDir();
372
373
        return $this->save($this->tmp_dir . $basename);
374
    }
375
}