Completed
Push — master ( 94ceed...ee25d4 )
by smiley
02:35
created

Video::__transform()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 6
Bugs 0 Features 1
Metric Value
c 6
b 0
f 1
dl 0
loc 15
rs 9.4285
cc 3
eloc 8
nc 3
nop 0
1
<?php
2
/**
3
 * Class Video
4
 *
5
 * @filesource   Video.php
6
 * @created      12.10.2015
7
 * @package      chillerlan\bbcode\Modules\Html5
8
 * @author       Smiley <[email protected]>
9
 * @copyright    2015 Smiley
10
 * @license      MIT
11
 */
12
13
namespace chillerlan\bbcode\Modules\Html5;
14
15
use chillerlan\bbcode\Modules\ModuleInterface;
16
use chillerlan\TinyCurl\Traits\RequestTrait;
17
18
/**
19
 * Transforms several video tags into HTML5
20
 *
21
 * @todo
22
 */
23
class Video extends Html5BaseModule implements ModuleInterface{
24
	use RequestTrait;
25
26
	/**
27
	 * An array of tags the module is able to process
28
	 *
29
	 * @var array
30
	 * @see \chillerlan\bbcode\Modules\Tagmap::$tags
31
	 */
32
	protected $tags = ['video', 'dmotion', 'vimeo', 'youtube', 'moddb'];
33
34
	/**
35
	 * temp flash
36
	 *
37
	 * @var string
38
	 */
39
	protected $flash;
40
41
	/**
42
	 * @var array
43
	 */
44
	protected $cssclass = ['bb-video'];
45
46
	/**
47
	 * Transforms the bbcode, called from BaseModuleInterface
48
	 *
49
	 * @return string a transformed snippet
50
	 * @see \chillerlan\bbcode\Modules\BaseModuleInterface::transform()
51
	 * @internal
52
	 */
53
	public function __transform():string{
54
		$this->setRequestCA($this->parserOptions->ca_info);
55
56
		if(empty($this->content)){
57
			return '';
58
		}
59
60
		$this->flash = $this->getAttribute('flash');
61
62
		if($this->getAttribute('wide')){
63
			$this->cssclass[] = 'wide';
64
		}
65
66
		return $this->getPlayer();
67
	}
68
69
	/**
70
	 * Gets the video provider
71
	 *
72
	 * @return string
73
	 */
74
	protected function getPlayer():string{
75
		$bbtag = $this->bbtag();
76
		$url   = parse_url($this->content);
77
		$host  = isset($url['host']) ? str_replace('www.', '', $url['host']) : false;
78
79
		switch(true){
80
			case $this->tag === 'vimeo' || $bbtag === 'vimeo' || $host === 'vimeo.com':
81
				return $this->vimeo();
82
			case $this->tag === 'youtube' || $bbtag === 'youtube' || in_array($host, ['youtube.com', 'youtu.be']):
83
				return $this->youtube($host, $url);
0 ignored issues
show
Security Bug introduced by
It seems like $url defined by parse_url($this->content) on line 76 can also be of type false; however, chillerlan\bbcode\Modules\Html5\Video::youtube() does only seem to accept array, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
84
			case $this->tag === 'moddb' || $bbtag === 'moddb' || $host === 'moddb.com':
85
				return $this->moddb($host, $url);
0 ignored issues
show
Security Bug introduced by
It seems like $url defined by parse_url($this->content) on line 76 can also be of type false; however, chillerlan\bbcode\Modules\Html5\Video::moddb() does only seem to accept array, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
86
			case $this->tag === 'dmotion' || $bbtag === 'dmotion' || in_array($host, ['dailymotion.com', 'dai.ly']):
87
				return $this->dailymotion($host, $url);
0 ignored issues
show
Security Bug introduced by
It seems like $url defined by parse_url($this->content) on line 76 can also be of type false; however, chillerlan\bbcode\Module...l5\Video::dailymotion() does only seem to accept array, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
88
			default:
89
				return $this->html5Player();
90
		}
91
92
	}
93
94
	/**
95
	 * @param string $video_url
96
	 *
97
	 * @return string
98
	 */
99
	protected function flashPlayer(string $video_url):string{
100
101
		return '<div'.$this->getCssClass($this->cssclass).'>'
102
		       .'<object type="application/x-shockwave-flash" data="'.$video_url.'">'
103
		       .'<param name="allowfullscreen" value="true">'
104
		       .'<param name="wmode" value="opaque" />'
105
		       .'<param name="movie" value="'.$video_url.'" />'
106
		       .'</object></div>';
107
	}
108
109
	/**
110
	 * @param string $video_url
111
	 *
112
	 * @return string
113
	 */
114
	protected function embedPlayer(string $video_url):string{
115
116
		return '<div'.$this->getCssClass($this->cssclass).'>'
117
		       .'<iframe src="'.$video_url.'" allowfullscreen></iframe></div>';
118
	}
119
120
	/**
121
	 * @return string
122
	 */
123
	protected function html5Player():string{
124
125
		return '<video src="'.$this->checkUrl($this->content).'"'
126
		       .$this->getCssClass($this->cssclass).' preload="auto" controls="true"></video>';
127
	}
128
129
	/**
130
	 * @param string $host
131
	 * @param array  $url
132
	 *
133
	 * @return string
134
	 */
135
	protected function dailymotion(string $host, array $url):string{
136
137
		if($host === 'dailymotion.com'){
138
			$id = explode('_', str_replace('/video/', '', $url['path']), 2)[0];
139
		}
140
		else if($host === 'dai.ly'){
141
			$id = $url['path'];
142
		}
143
		else{
144
			$id = $this->content;
145
		}
146
147
		$id = preg_replace('#[^a-z\d]#i', '', $id);
148
149
		return $this->flash
150
			? $this->flashPlayer('http://www.dailymotion.com/swf/video/'.$id)
151
			: $this->embedPlayer('http://www.dailymotion.com/embed/video/'.$id);
152
	}
153
154
	/**
155
	 * @param string $host
156
	 * @param array  $url
157
	 *
158
	 * @return string
159
	 */
160
	protected function moddb(string $host, array $url):string{
161
162
		$id = $host === 'moddb.com' && strpos('http://www.moddb.com/media/', $this->content) === 0
163
			? $url['path']
164
			: $this->content;
165
166
		$id = preg_replace('/[^\d]/', '', $id);
167
168
		return $this->flash
169
			? $this->flashPlayer('http://www.moddb.com/media/embed/'.$id)
170
			: $this->embedPlayer('http://www.moddb.com/media/iframe/'.$id);
171
	}
172
173
	/**
174
	 * @return string
175
	 */
176
	protected function vimeo():string{
177
		// since the video id is the only numeric part in a common vimeo share url, we can safely strip anything which is not number
178
		$id = preg_replace('/[^\d]/', '', $this->content);
179
180
		// @todo collect & batch request
181
		$response = $this->fetch('https://api.vimeo.com/videos/'.$id, ['access_token' => $this->parserOptions->vimeo_access_token])->json;
182
183
		// access token needed - no coverage
184
		// @codeCoverageIgnoreStart
185
		if(isset($response->link)){
186
			// @todo add fancyness
187
			return $this->flash
188
				? $this->flashPlayer('https://vimeo.com/moogaloop.swf?clip_id='.$id)
189
				: $this->embedPlayer('https://player.vimeo.com/video/'.$id);
190
		}
191
		// @codeCoverageIgnoreEnd
192
193
		return '';
194
	}
195
196
	/**
197
	 * @param string $host
198
	 * @param array  $url
199
	 *
200
	 * @return string
201
	 */
202
	protected function youtube(string $host, array $url):string{
203
204
		if($host === 'youtube.com'){
205
			parse_str($url['query'], $q);
206
			$id = $q['v'];
207
		}
208
		else if($host === 'youtu.be'){
209
			$e = explode('/', $url['path'], 2);
210
			$id = isset($e[1]) ? $e[1] : false;
211
		}
212
		else{
213
			$id = $this->content;
214
		}
215
216
		if($id){
217
218
			// check video (and get data)
219
			$params = [
220
				'id' => preg_replace('/[^a-z\d-_]/i', '', $id),
221
				'part' => 'snippet',
222
				'key' => $this->parserOptions->google_api_key,
223
			];
224
225
			$response = $this->fetch('https://www.googleapis.com/youtube/v3/videos', $params)->json;
226
227
			// api key needed - no coverage
228
			// @codeCoverageIgnoreStart
229
			if(isset($response->items, $response->items[0]) && $response->items[0]->id === $id){
230
				// @todo support playlists
231
				return $this->flash
232
					? $this->flashPlayer('https://www.youtube.com/v/'.$id)
233
					: $this->embedPlayer('https://www.youtube.com/embed/'.$id);
234
			}
235
			// @codeCoverageIgnoreEnd
236
		}
237
238
		return '';
239
	}
240
241
}
242