Completed
Push — master ( 9b2ed5...981814 )
by Jeroen De
76:07
created

formats/media/MediaPlayer.php (5 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace SRF;
4
5
use File;
6
use FormatJson;
7
use Html;
8
use Skin;
9
use SMW\ResultPrinter;
10
use SMWDataItem;
11
use SMWDataValue;
12
use SMWOutputs;
13
use SMWQueryResult;
14
use SRFUtils;
15
use Title;
16
17
/**
18
 * HTML5 Audio / Video media query printer
19
 *
20
 * This printer integrates jPlayer which is a HTML5 Audio / Video
21
 * Javascript libray under GPL/MIT license.
22
 *
23
 * @see http://www.semantic-mediawiki.org/wiki/Help:Media_format
24
 *
25
 * @since 1.9
26
 *
27
 * @file
28
 * @ingroup SRF
29
 * @ingroup QueryPrinter
30
 *
31
 * @licence GNU GPL v2 or later
32
 * @author mwjames
33
 */
34
35
/**
36
 * This printer integrates jPlayer which is a HTML5 Audio / Video
37
 * Javascript libray under GPL/MIT license.
38
 *
39
 * @ingroup SRF
40
 * @ingroup QueryPrinter
41
 */
42
class MediaPlayer extends ResultPrinter {
43
44
	/**
45
	 * Specifies valid mime types supported by jPlayer
46
	 *
47
	 * @var array
48
	 */
49
	protected $validMimeTypes = [ 'mp3', 'mp4', 'webm', 'webma', 'webmv', 'ogg', 'oga', 'ogv', 'm4v', 'm4a' ];
50
51
	/**
52
	 * @see SMWResultPrinter::getName
53
	 * @return string
54
	 */
55
	public function getName() {
56
		return $this->msg( 'srf-printername-media' )->text();
57
	}
58
59
	/**
60
	 * @see SMWResultPrinter::getResultText
61
	 *
62
	 * @param SMWQueryResult $result
63
	 * @param $outputMode
64
	 *
65
	 * @return string
66
	 */
67
	protected function getResultText( SMWQueryResult $result, $outputMode ) {
68
69
		// Data processing
70
		$data = $this->getResultData( $result, $outputMode );
71
72
		// Check if the data processing returned any results otherwise just bailout
73
		if ( $data === [] ) {
74
			if ( $this->params['default'] !== '' ) {
75
				return $this->params['default'];
76
			} else {
77
				$result->addErrors( [ $this->msg( 'srf-no-results' )->inContentLanguage()->text() ] );
78
				return '';
79
			}
80
		} else {
81
			// Return formatted results
82
			return $this->getFormatOutput( $data );
83
		}
84
	}
85
86
	/**
87
	 * Returns an array with data
88
	 *
89
	 * @since 1.9
90
	 *
91
	 * @param SMWQueryResult $result
92
	 * @param $outputMode
93
	 *
94
	 * @return array
95
	 */
96
	protected function getResultData( SMWQueryResult $result, $outputMode ) {
97
98
		$data = [];
99
100
		/**
101
		 * Get all values for all rows that belong to the result set
102
		 *
103
		 * @var SMWResultArray $rows
104
		 */
105
		while ( $rows = $result->getNext() ) {
106
			$rowData = [];
107
			$mediaType = null;
108
			$mimeType = null;
109
110
			/**
111
			 * @var SMWResultArray $field
112
			 * @var SMWDataValue $dataValue
113
			 */
114
			foreach ( $rows as $field ) {
115
116
				// Label for the current property
117
				$propertyLabel = $field->getPrintRequest()->getLabel();
118
119
				// Label for the current subject
120
				$subjectLabel = $field->getResultSubject()->getTitle()->getFullText();
121
122
				if ( $propertyLabel === '' || $propertyLabel === '-' ) {
123
					$propertyLabel = 'subject';
124
				} elseif ( $propertyLabel === 'poster' ) {
125
					// Label "poster" is a special case where we set the media type to video in order
126
					// to use the same resources that can display video and cover art
127
					// $data['mediaTypes'][] = 'video';
128
				}
129
130
				// Check if the subject itself is a media source
131
				if ( $field->getResultSubject()->getTitle()->getNamespace() === NS_FILE && $mimeType === null ) {
132
					list( $mediaType, $mimeType, $source ) = $this->getMediaSource(
133
						$field->getResultSubject()->getTitle()
134
					);
135
					$rowData[$mimeType] = $source;
136
				}
137
138
				while ( ( $dataValue = $field->getNextDataValue() ) !== false ) {
139
					// Get other data value item details
140
					$value = $this->getDataValueItem(
141
						$propertyLabel,
142
						$dataValue->getDataItem()->getDIType(),
143
						$dataValue,
144
						$mediaType,
145
						$mimeType,
146
						$rowData
147
					);
148
					$rowData[$propertyLabel] = $value;
149
				}
150
			}
151
152
			// Only select relevant source data that match the validMimeTypes
153
			if ( $mimeType !== '' && in_array( $mimeType, $this->validMimeTypes ) ) {
154
				$data['mimeTypes'][] = $mimeType;
155
				$data['mediaTypes'][] = $mediaType;
156
				$data[$subjectLabel] = $rowData;
0 ignored issues
show
The variable $subjectLabel does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
157
			}
158
		}
159
160
		return $data;
161
	}
162
163
	/**
164
	 * Returns media source information
165
	 *
166
	 * @since 1.9
167
	 *
168
	 * @param Title $title
169
	 */
170
	private function getMediaSource( Title $title ) {
171
172
		// Find the file source
173
		$source = wfFindFile( $title );
174
		if ( $source ) {
175
			// $source->getExtension() returns ogg even though it is a ogv/oga (same goes for m4p) file
176
			// this doesn't help much therefore we do it ourselves
177
			$extension = $source->getExtension();
178
179
			if ( in_array( $extension, [ 'ogg', 'oga', 'ogv' ] ) ) {
180
				$extension = strtolower( substr( $source->getName(), strrpos( $source->getName(), '.' ) + 1 ) );
181
182
				// Xiph.Org recommends that .ogg only be used for Ogg Vorbis audio files
183
				$extension = $extension === 'ogg' ? 'oga' : $extension;
184
185
				$params = [ $extension === 'ogv' ? 'video' : 'audio', $extension, $source->getUrl() ];
186
			} elseif ( in_array( $extension, [ 'm4v', 'm4a', 'm4p' ] ) ) {
187
				$params = [ $extension === 'm4v' ? 'video' : 'audio', $extension, $source->getUrl() ];
188
			} else {
189
				list( $major, $minor ) = File::splitMime( $source->getMimeType() );
190
				$params = [ $major, $extension, $source->getUrl() ];
191
			}
192
		} else {
193
			$params = [];
194
		}
195
		return $params;
196
	}
197
198
	/**
199
	 * Returns single data value item
200
	 *
201
	 * @since 1.9
202
	 *
203
	 * @param string $label
204
	 * @param integer $type
205
	 * @param SMWDataValue $dataValue
206
	 * @param string $mediaType
207
	 * @param string $mimeType
208
	 *
209
	 * @return mixed
210
	 */
211
	private function getDataValueItem( &$label, $type, SMWDataValue $dataValue, &$mediaType, &$mimeType, &$rowData ) {
212
213
		if ( $type == SMWDataItem::TYPE_WIKIPAGE && $dataValue->getTitle()->getNamespace() === NS_FILE ) {
0 ignored issues
show
It seems like you code against a specific sub-type and not the parent class SMWDataValue as the method getTitle() does only exist in the following sub-classes of SMWDataValue: SMWWikiPageValue. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
214
215
			if ( $label === 'source' && $mimeType === null ) {
216
217
				// Identify the media source
218
				// and get media information
219
				list( $mediaType, $mimeType, $source ) = $this->getMediaSource( $dataValue->getTitle() );
0 ignored issues
show
It seems like you code against a specific sub-type and not the parent class SMWDataValue as the method getTitle() does only exist in the following sub-classes of SMWDataValue: SMWWikiPageValue. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
220
				$label = $mimeType;
221
				return $source;
222
			} elseif ( $label === 'poster' ) {
223
				$mediaType = 'video';
224
225
				// Get the cover art image url
226
				$source = wfFindFile( $dataValue->getTitle() );
0 ignored issues
show
It seems like you code against a specific sub-type and not the parent class SMWDataValue as the method getTitle() does only exist in the following sub-classes of SMWDataValue: SMWWikiPageValue. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
227
				return $source->getUrl();
228
			}
229
		}
230
231
		if ( $type == SMWDataItem::TYPE_URI ) {
232
233
			$source = $dataValue->getDataItem()->getURI();
0 ignored issues
show
It seems like you code against a specific sub-type and not the parent class SMWDataItem as the method getURI() does only exist in the following sub-classes of SMWDataItem: SMWDIUri. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
234
			$mimeType = '';
235
236
			// Get file extension from the URI
237
			$extension = strtolower( substr( $source, strrpos( $source, '.' ) + 1 ) );
238
239
			// Xiph.Org recommends that .ogg only be used for Ogg Vorbis audio files
240
			if ( in_array( $extension, [ 'ogg', 'oga', 'ogv' ] ) ) {
241
				$mimeType = $extension === 'ogg' ? 'oga' : $extension;
242
				$mediaType = $extension === 'ogv' ? 'video' : 'audio';
243
			} elseif ( in_array( $extension, [ 'm4v', 'm4a', 'm4p' ] ) ) {
244
				$mimeType = $extension;
245
				$mediaType = $extension === 'm4v' ? 'video' : 'audio';
246
			} else {
247
				$mimeType = $extension;
248
				$mediaType = strpos( $extension, 'v' ) !== false ? 'video' : 'audio';
249
			}
250
251
			if ( $mimeType !== '' ) {
252
				$rowData[$mimeType] = $source;
253
			}
254
255
			return $source;
256
		}
257
258
		return $dataValue->getWikiValue();
259
	}
260
261
	/**
262
	 * Prepare data for the output
263
	 *
264
	 * @since 1.9
265
	 *
266
	 * @param array $data
267
	 *
268
	 * @return string
269
	 */
270
	protected function getFormatOutput( $data ) {
271
272
		$ID = 'srf-' . uniqid();
273
		$this->isHTML = true;
274
275
		// Get the media/mime types
276
		if ( in_array( 'video', $data['mediaTypes'] ) ) {
277
			$mediaType = 'video';
278
		} else {
279
			$mediaType = 'audio';
280
		}
281
		unset( $data['mediaTypes'] );
282
283
		$mimeTypes = array_unique( $data['mimeTypes'] );
284
		unset( $data['mimeTypes'] );
285
286
		// Reassign output array
287
		$output = [
288
			'data' => $data,
289
			'count' => count( $data ),
290
			'mediaType' => $mediaType,
291
			'mimeTypes' => implode( ',', $mimeTypes ),
292
			'inspector' => $this->params['inspector']
293
		];
294
295
		$requireHeadItem = [ $ID => FormatJson::encode( $output ) ];
296
		SMWOutputs::requireHeadItem( $ID, Skin::makeVariablesScript( $requireHeadItem ) );
297
298
		SMWOutputs::requireResource( 'ext.jquery.jplayer.skin.' . $this->params['theme'] );
299
		SMWOutputs::requireResource( 'ext.srf.formats.media' );
300
301
		$processing = SRFUtils::htmlProcessingElement();
302
303
		return Html::rawElement(
304
			'div',
305
			[
306
				'class' => $this->params['class'] !== '' ? 'srf-media ' . $this->params['class'] : 'srf-media'
307
			],
308
			$processing . Html::element(
309
				'div',
310
				[
311
					'id' => $ID,
312
					'class' => 'media-container',
313
					'style' => 'display:none;'
314
				],
315
				null
316
			)
317
		);
318
	}
319
320
	/**
321
	 * @see SMWResultPrinter::getParamDefinitions
322
	 *
323
	 * @since 1.9
324
	 *
325
	 * @param $definitions array of IParamDefinition
326
	 *
327
	 * @return array of IParamDefinition|array
328
	 */
329
	public function getParamDefinitions( array $definitions ) {
330
		$params = parent::getParamDefinitions( $definitions );
331
332
		$params['class'] = [
333
			'message' => 'srf-paramdesc-class',
334
			'default' => '',
335
		];
336
337
		$params['theme'] = [
338
			'message' => 'srf-paramdesc-theme',
339
			'default' => 'blue.monday',
340
			'values' => [ 'blue.monday', 'morning.light' ],
341
		];
342
343
		$params['inspector'] = [
344
			'type' => 'boolean',
345
			'message' => 'srf-paramdesc-mediainspector',
346
			'default' => false,
347
		];
348
349
		return $params;
350
	}
351
}
352