Video::maybeRutube()   B
last analyzed

Complexity

Conditions 7
Paths 7

Size

Total Lines 19
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 9
dl 0
loc 19
rs 8.8333
c 0
b 0
f 0
cc 7
nc 7
nop 1
1
<?php namespace Helpers;
2
3
/**
4
 * Использование:
5
 * $v = new VideoThumb($link);
6
 * $v->getVideo(); //Ссылка на видео
7
 * $v->getTitle(); //Название ролика
8
 * $v->fetchImage($path) //Скачать самое большое превью ролика
9
 *
10
 * Прогнать тест:
11
 * VideoThumb::RunTest()
12
 * @See: https://gist.github.com/cmsx/5539570
13
 */
14
class Video
15
{
16
    /** Ссылка на ролик */
17
    protected $link;
18
19
    /** Распарсенные части ссылки */
20
    protected $link_parts;
21
22
    /** Видеохостинг */
23
    protected $hosting;
24
25
    /** Идентификатор видео */
26
    protected $id;
27
28
    /** Картинка */
29
    protected $image;
30
31
    /** Название видео */
32
    protected $title;
33
34
    /** Видео */
35
    protected $video;
36
37
    protected $width = 420;
38
    protected $height = 315;
39
    protected $autoplay = false;
40
41
    public $scheme = 'https';
42
43
    const YOUTUBE = 'youtube';
44
    const VIMEO = 'vimeo';
45
    const RUTUBE = 'rutube';
46
47
    /** Регулярки для определения видеохостинга и идентификатора ролика */
48
    protected $regexp = array(
49
        self::YOUTUBE => array( //Не используются
50
            '/[http|https]+:\/\/(?:www\.|)youtube\.com\/watch\?(?:.*)?v=([a-zA-Z0-9_\-]+)/i',
51
            '/[http|https]+:\/\/(?:www\.|)youtube\.com\/embed\/([a-zA-Z0-9_\-]+)/i',
52
            '/[http|https]+:\/\/(?:www\.|)youtu\.be\/([a-zA-Z0-9_\-]+)/i'
53
        ),
54
        self::VIMEO   => array( //Не используются
55
            '/[http|https]+:\/\/(?:www\.|)vimeo\.com\/([a-zA-Z0-9_\-]+)(&.+)?/i',
56
            '/[http|https]+:\/\/player\.vimeo\.com\/video\/([a-zA-Z0-9_\-]+)(&.+)?/i'
57
        ),
58
        self::RUTUBE  => array(
59
            '/[http|https]+:\/\/(?:www\.|)rutube\.ru\/video\/embed\/([a-zA-Z0-9_\-]+)/i',
60
            '/[http|https]+:\/\/(?:www\.|)rutube\.ru\/tracks\/([a-zA-Z0-9_\-]+)(&.+)?/i'
61
        )
62
    );
63
64
    /** Ссылка на RUtube без идентификатора в адресе */
65
    protected $regexp_rutube_extra = '/[http|https]+:\/\/(?:www\.|)rutube\.ru\/video\/([a-zA-Z0-9_\-]+)\//i';
66
67
    /** Варианты ссылок, которые поддерживаются */
68
    protected static $test = array(
69
        'http://youtube.com/watch?v=ShPq2Dmy6X8',
70
        'http://www.youtube.com/watch?v=6dwqZw0j_jY&feature=youtu.be',
71
        'http://www.youtube.com/watch?v=cKZDdG9FTKY&feature=channel',
72
        'www.youtube.com/watch?v=yZ-K7nCVnBI&playnext_from=TL&videos=osPknwzXEas&feature=sub',
73
        'http://www.youtube.com/embed/ShPq2Dmy6X8?rel=0',
74
        'http://youtu.be/ShPq2Dmy6X8',
75
        'youtu.be/6dwqZw0j_jY',
76
        'http://www.youtu.be/afa-5HQHiAs',
77
        'vimeo.com/55028438',
78
        'http://player.vimeo.com/video/55028438?title=0&byline=0&portrait=0&badge=0&color=e1a931',
79
        'http://rutube.ru/video/6fd81c1c212c002673280850a1c56415/#.UMQYln9yTWQ',
80
        'http://rutube.ru/video/dec0a58c8cb4d226abc7b1030bbb63b9/?ref=top',
81
        'rutube.ru/tracks/6032725.html',
82
        'http://www.rutube.ru/video/embed/6032725',
83
    );
84
85
    protected $info = false;
86
87
    /**
88
     * @param string|null $link ссылка на видео
89
     * @param bool $autostart сразу определить превью и клип
90
     */
91
    public function __construct($link = null, $autostart = true, $info = false)
92
    {
93
        if (! empty($link)) {
94
            $this->setLink($link);
95
            $this->setInfo($info);
96
            if ($autostart) {
97
                $this->process();
98
            }
99
        }
100
    }
101
102
    /**
103
     * @return string
104
     */
105
    public function getScheme()
106
    {
107
        switch ($this->scheme) {
108
            case 'http':
109
                $out = 'http://';
110
                break;
111
            case 'https':
112
                $out = 'https://';
113
                break;
114
            default:
115
                $out = '//';
116
                break;
117
        }
118
119
        return $out;
120
    }
121
122
    /**
123
     * @param $info
124
     */
125
    public function setInfo($info)
126
    {
127
        $this->info = (bool)$info;
128
    }
129
130
    /**
131
     * @return bool
132
     */
133
    public function getInfo()
134
    {
135
        return $this->info;
136
    }
137
138
    /** Видеохостинг */
139
    public function getHosting()
140
    {
141
        return $this->hosting;
142
    }
143
144
    /** Идентификатор видео */
145
    public function getId()
146
    {
147
        return $this->id;
148
    }
149
150
    /** Ссылка на превью */
151
    public function getImage()
152
    {
153
        return $this->getScheme() . $this->image;
154
    }
155
156
    /** Ссылка на видео */
157
    public function getVideo($autoplay = false)
158
    {
159
        $url = $this->video;
160
        if ($autoplay) {
161
            $url .= '&autoplay=1';
162
        }
163
164
        return $this->getScheme() . $url;
165
    }
166
167
    /** Название видео */
168
    public function getTitle()
169
    {
170
        return $this->title;
171
    }
172
173
    /** Задать ссылку на видео */
174
    public function setLink($link)
175
    {
176
        $this->link = $link;
177
178
        return $this;
179
    }
180
181
    /** Обработка ссылки. Возвращает идентификатор видеохостинга или false */
182
    public function process($link = null, $info = null)
183
    {
184
        if (! empty($link)) {
185
            $this->setLink($link);
186
        }
187
        if (! empty($info)) {
188
            $this->setInfo($info);
189
        }
190
191
        if ($this->cleanLink()) {
192
            if ($this->maybeYoutube()) {
193
                return self::YOUTUBE;
194
            }
195
196
            if ($this->maybeVimeo()) {
197
                return self::VIMEO;
198
            }
199
200
            if ($this->maybeRutube()) {
201
                return self::RUTUBE;
202
            }
203
        }
204
205
        return false;
206
    }
207
208
    /** Скачать превью. Если не указать имя файла для записи - функция вернет содержимое файла */
209
    public function fetchImage($filename = null)
210
    {
211
        if (! $url = $this->getImage()) {
212
            return false;
213
        }
214
215
        if (! $res = $this->fetchPage($url)) {
216
            return false;
217
        }
218
219
        return $filename
220
            ? file_put_contents($filename, $res)
221
            : $res;
222
    }
223
224
    /** Проверка и подготовка ссылки и частей */
225
    protected function cleanLink()
226
    {
227
        if (!preg_match('/^(http|https)\:\/\//i', $this->link)) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after NOT operator; 0 found
Loading history...
228
            $this->link = 'http://' . $this->link;
229
        }
230
231
        if (! $this->link_parts = parse_url($this->link)) {
232
            return false;
233
        }
234
235
        return true;
236
    }
237
238
    /** Проверка YOUTUBE */
239
    protected function maybeYoutube()
240
    {
241
        $h = str_replace('www.', '', $this->link_parts['host']);
242
        $p = isset($this->link_parts['path']) ? $this->link_parts['path'] : false;
243
244
        if ('youtube.com' == $h) {
245
            parse_str($this->link_parts['query'], $q);
246
247
            if ('/watch' == $p && ! empty($q['v'])) {
248
                return $this->foundYoutube($q['v']);
249
            }
250
            if (0 === strpos($p, '/embed/')) {
0 ignored issues
show
Bug introduced by
It seems like $p can also be of type false; however, parameter $haystack of strpos() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

250
            if (0 === strpos(/** @scrutinizer ignore-type */ $p, '/embed/')) {
Loading history...
251
                return $this->foundYoutube(str_replace('/embed/', '', $p));
252
            }
253
        } elseif ('youtu.be' == $h) {
254
            return $this->foundYoutube(trim($p, '/'));
0 ignored issues
show
Bug introduced by
It seems like $p can also be of type false; however, parameter $string of trim() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

254
            return $this->foundYoutube(trim(/** @scrutinizer ignore-type */ $p, '/'));
Loading history...
255
        }
256
257
        return false;
258
    }
259
260
    /** Проверка VIMEO */
261
    protected function maybeVimeo()
262
    {
263
        $h = str_replace('www.', '', $this->link_parts['host']);
264
        $p = isset($this->link_parts['path']) ? $this->link_parts['path'] : false;
265
266
        if ('vimeo.com' == $h) {
267
            return $this->foundVimeo(trim($p, '/'));
0 ignored issues
show
Bug introduced by
It seems like $p can also be of type false; however, parameter $string of trim() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

267
            return $this->foundVimeo(trim(/** @scrutinizer ignore-type */ $p, '/'));
Loading history...
268
        } elseif ('player.vimeo.com' == $h && 0 === strpos($p, '/video/')) {
0 ignored issues
show
Bug introduced by
It seems like $p can also be of type false; however, parameter $haystack of strpos() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

268
        } elseif ('player.vimeo.com' == $h && 0 === strpos(/** @scrutinizer ignore-type */ $p, '/video/')) {
Loading history...
269
            return $this->foundVimeo(str_replace('/video/', '', $p));
270
        }
271
272
        return false;
273
    }
274
275
    /** Проверка RUTUBE */
276
    protected function maybeRutube($html = null)
277
    {
278
        $link = $html ?: $this->link;
279
280
        foreach ($this->regexp[self::RUTUBE] as $regexp) {
281
            if (preg_match($regexp, $link, $matches)) {
282
                return $this->foundRutube($matches[1]);
283
            }
284
        }
285
286
        // Проверка на особенную ссылку RUtube`a
287
        if (is_null($html) && preg_match($this->regexp_rutube_extra, $this->link, $matches)) {
288
            $html = $this->fetchPage($matches[0]);
289
            if ($r = $this->maybeRutube($html)) {
290
                return $r;
291
            }
292
        }
293
294
        return false;
295
    }
296
297
    /** Обработка YOUTUBE */
298
    protected function foundYoutube($id)
299
    {
300
        if (empty($id) || strlen($id) != 11) {
301
            return false;
302
        }
303
304
        $this->hosting = self::YOUTUBE;
305
        $this->id = $id;
306
        $this->image = 'img.youtube.com/vi/' . $id . '/0.jpg';
307
        /** @see https://developers.google.com/youtube/player_parameters */
308
        $this->video = 'www.youtube.com/embed/' . $id . '?showinfo=0&modestbranding=1&rel=0';
309
310
        if ($this->info) {
311
            $this->getYoutubeInfo($id);
312
        }
313
314
        return true;
315
    }
316
317
    /** Обработка VIMEO */
318
    protected function foundVimeo($id)
319
    {
320
        if (empty($id) || !is_numeric($id)) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after NOT operator; 0 found
Loading history...
321
            return false;
322
        }
323
324
        $this->hosting = self::VIMEO;
325
        $this->id = $id;
326
        $this->video = 'player.vimeo.com/video/' . $id . '?';
327
328
        if ($this->info) {
329
            $this->getVimeoInfo($id);
330
        }
331
332
        return true;
333
    }
334
335
    /** Обработка RUTUBE */
336
    protected function foundRutube($id)
337
    {
338
        $this->hosting = self::RUTUBE;
339
        $this->id = $id;
340
        $this->video = 'rutube.ru/video/embed/' . $id . '?';
341
342
        if ($this->info) {
343
            $this->getRutubeInfo($id);
344
        }
345
346
        return true;
347
    }
348
349
    /** Парсинг XML от RUTUBE и определение превьюхи */
350
    protected function getRutubeInfo($id)
351
    {
352
        if (@$xml = simplexml_load_file("http://rutube.ru/cgi-bin/xmlapi.cgi?rt_mode=movie&rt_movie_id=" . $id . "&utf=1")) {
353
            $this->title = (string)$xml->title;
354
            $this->image = (string)$xml->thumbnail_url;
355
        }
356
    }
357
358
    /** Парсинг XML от VIMEO и определение превьюхи */
359
    protected function getVimeoInfo($id)
360
    {
361
        if (@$xml = simplexml_load_file('http://vimeo.com/api/v2/video/' . $id . '.xml')) {
362
            $this->title = (string)$xml->video->title;
363
            $this->image = (string)$xml->video->thumbnail_large ?: $xml->video->thumbnail_medium;
364
        }
365
    }
366
367
    /** Получение названия ролика */
368
    protected function getYoutubeInfo($id)
369
    {
370
        if (@$xml = simplexml_load_file('http://gdata.youtube.com/feeds/api/videos/' . $id)) {
371
            $this->title = (string)$xml->title;
372
        }
373
    }
374
375
    /** Скачивание страницы с помощью CURL */
376
    protected function fetchPage($url)
377
    {
378
        $ch = curl_init();
379
        curl_setopt($ch, CURLOPT_URL, $url);
380
        curl_setopt($ch, CURLOPT_FAILONERROR, true);
381
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
382
        curl_setopt($ch, CURLOPT_TIMEOUT, 3);
383
384
        return curl_exec($ch);
385
    }
386
387
    /**
388
     * @param $options
389
     * @return string
390
     */
391
    public function getEmbed($options)
392
    {
393
        $autoplay = isset($options["autoplay"]) ? $options["autoplay"] : $this->autoplay;
394
        $width = isset($options["width"]) ? (int)$options["width"] : $this->width;
395
        $height = isset($options["height"]) ? (int)$options["height"] : $this->height;
396
        $class = isset($options['class']) ? $options['class'] : '';
397
398
        $url = $this->getVideo($autoplay);
399
        if (! empty($class)) {
400
            $class = ' class="' . $class . '"';
401
        }
402
403
        return '<iframe src="' . $url . '" width="' . $width . '" height="' . $height . '" frameborder="0" allowfullscreen' . $class . '></iframe>';
404
    }
405
406
    /** Прогоняем тест по видам URL */
407
    public static function RunTest($links = null)
0 ignored issues
show
Coding Style introduced by
Method name "Video::RunTest" is not in camel caps format
Loading history...
Coding Style introduced by
This method is not in camel caps format.

This check looks for method names that are not written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection seeker becomes databaseConnectionSeeker.

Loading history...
408
    {
409
        if (!is_array($links)) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after NOT operator; 0 found
Loading history...
410
            $links = static::$test;
411
        }
412
413
        foreach ($links as $link) {
414
            $v = new static($link);
415
            echo "<h1>$link</h1>\n"
416
                . "<h3>" . $v->getHosting() . "</h3>"
417
                . "<b>Видео:</b> " . $v->getVideo() . "<br />\n"
418
                . "<b>Название:</b> " . $v->getTitle() . "<br />\n"
419
                . "<b>Картинка:</b> " . $v->getImage() . "<hr />\n";
420
        }
421
    }
422
423
}
424