Passed
Push — master ( 4c970b...bd012b )
by Amin
03:15
created

Export::getPath()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 1
Metric Value
cc 3
eloc 10
c 1
b 1
f 1
nc 3
nop 0
dl 0
loc 15
rs 9.9332
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
            $this->tmp_dir = '';
170
        }
171
    }
172
173
    /**
174
     * @return array
175
     */
176
    public function getPathInfo(): array
177
    {
178
        return $this->path_info;
179
    }
180
181
    /**
182
     * @return object|Media
183
     */
184
    public function getMedia(): Media
185
    {
186
        return $this->media;
187
    }
188
189
    /**
190
     * @param string $strict
191
     * @return Export
192
     */
193
    public function setStrict(string $strict): Export
194
    {
195
        $this->strict = $strict;
196
        return $this;
197
    }
198
199
    /**
200
     * @return string
201
     */
202
    public function getStrict(): string
203
    {
204
        return $this->strict;
205
    }
206
207
    /**
208
     * @return bool
209
     */
210
    public function isTmpDir(): bool
211
    {
212
        return (bool)$this->tmp_dir;
213
    }
214
215
    /**
216
     * clear tmp files
217
     */
218
    public function __destruct()
219
    {
220
        sleep(1);
221
222
        if ($this->media->isTmp()) {
223
            @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

223
            /** @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...
224
        }
225
226
        if ($this->tmp_dir) {
227
            FileManager::deleteDirectory($this->tmp_dir);
228
        }
229
230
        if ($this instanceof HLS && $this->tmp_key_info_file) {
231
            @unlink($this->getHlsKeyInfoFile());
232
        }
233
    }
234
235
    /**
236
     * @param string $url
237
     * @param string $name
238
     * @param string|null $path
239
     * @param string $method
240
     * @param array $headers
241
     * @param array $options
242
     * @return mixed
243
     * @throws Exception
244
     * @deprecated this method is deprecated
245
     */
246
    // @TODO: should be removed in the next releases.
247
    public function saveToCloud(
248
        string $url,
249
        string $name,
250
        string $path = null,
251
        string $method = 'GET',
252
        array $headers = [],
253
        array $options = []
254
    )
255
    {
256
        @trigger_error('saveToCloud method is deprecated and will be removed in a future release. Use Cloud instead', E_USER_DEPRECATED);
257
        if ($this instanceof HLS && $this->getTsSubDirectory()) {
258
            throw new InvalidArgumentException("It is not possible to create subdirectory in a cloud");
259
        }
260
        $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

260
        $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...
261
        sleep(1);
262
263
        $cloud = new Cloud($url, $method, $options);
264
        $cloud->uploadDirectory($this->tmp_dir, ['name' => $name, 'headers' => $headers]);
265
266
        $this->moveTmpFolder($path);
267
268
        return $results;
269
    }
270
271
    /**
272
     * @param array $config
273
     * @param string $dest
274
     * @param string|null $path
275
     * @return mixed
276
     * @throws Exception
277
     * @deprecated this method is deprecated
278
     */
279
    // @TODO: should be removed in the next releases.
280
    public function saveToS3(
281
        array $config,
282
        string $dest,
283
        string $path = null
284
    )
285
    {
286
        @trigger_error('saveToS3 method is deprecated and will be removed in a future release. Use AWS instead', E_USER_DEPRECATED);
287
        $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

287
        $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...
288
        sleep(1);
289
290
        $aws = new AWS($config);
291
        $aws->uploadDirectory($this->tmp_dir, ['dest' => $dest]);
292
293
        $this->moveTmpFolder($path);
294
295
        return $results;
296
    }
297
298
    /**
299
     * @param array $config
300
     * @param string $bucket
301
     * @param string|null $path
302
     * @param array $options
303
     * @param bool $userProject
304
     * @return mixed
305
     * @throws Exception
306
     * @deprecated this method is deprecated
307
     */
308
    // @TODO: should be removed in the next releases.
309
    public function saveToGCS(
310
        array $config,
311
        string $bucket,
312
        string $path = null,
313
        array $options = [],
314
        bool $userProject = false
315
    )
316
    {
317
        @trigger_error('saveToGCS method is deprecated and will be removed in a future release. Use GoogleCloudStorage instead', E_USER_DEPRECATED);
318
        if ($this instanceof HLS && $this->getTsSubDirectory()) {
319
            throw new InvalidArgumentException("It is not possible to create subdirectory in a cloud");
320
        }
321
322
        $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

322
        $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...
323
        sleep(1);
324
325
        $google_cloud = new GoogleCloudStorage($config, $bucket, $userProject);
326
        $google_cloud->uploadDirectory($this->tmp_dir, $options);
327
328
        $this->moveTmpFolder($path);
329
330
        return $results;
331
    }
332
333
    /**
334
     * @param string $connectionString
335
     * @param string $container
336
     * @param string|null $path
337
     * @return mixed
338
     * @throws Exception
339
     * @deprecated this method is deprecated
340
     */
341
    // @TODO: should be removed in the next releases.
342
    public function saveToMAS(
343
        string $connectionString,
344
        string $container,
345
        string $path = null
346
    )
347
    {
348
        @trigger_error('saveToMAS method is deprecated and will be removed in a future release. Use MicrosoftAzure instead', E_USER_DEPRECATED);
349
350
        if ($this instanceof HLS && $this->getTsSubDirectory()) {
351
            throw new InvalidArgumentException("It is not possible to create subdirectory in a cloud");
352
        }
353
354
        $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

354
        $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...
355
        sleep(1);
356
357
        $google_cloud = new MicrosoftAzure($connectionString);
358
        $google_cloud->uploadDirectory($this->tmp_dir, ['container' => $container]);
359
360
        $this->moveTmpFolder($path);
361
362
        return $results;
363
    }
364
365
    /**
366
     * @param $path
367
     * @return array
368
     * @throws Exception
369
     * @deprecated this method is deprecated
370
     */
371
    // @TODO: should be removed in the next releases.
372
    private function saveToTemporaryFolder($path)
373
    {
374
        $basename = Helper::randomString();
375
376
        if (null !== $path) {
377
            $basename = pathinfo($path, PATHINFO_BASENAME);
378
        }
379
380
        $this->tmp_dir = FileManager::tmpDir();
381
382
        return $this->save($this->tmp_dir . $basename);
383
    }
384
}