This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /** |
||
4 | * @package Pods\Fields |
||
5 | */ |
||
6 | class PodsField_OEmbed extends PodsField { |
||
7 | |||
8 | /** |
||
9 | * {@inheritdoc} |
||
10 | */ |
||
11 | public static $group = 'Relationships / Media'; |
||
12 | |||
13 | /** |
||
14 | * {@inheritdoc} |
||
15 | */ |
||
16 | public static $type = 'oembed'; |
||
17 | |||
18 | /** |
||
19 | * {@inheritdoc} |
||
20 | */ |
||
21 | public static $label = 'oEmbed'; |
||
22 | |||
23 | /** |
||
24 | * {@inheritdoc} |
||
25 | */ |
||
26 | public static $prepare = '%s'; |
||
27 | |||
28 | /** |
||
29 | * Available oEmbed providers |
||
30 | * |
||
31 | * @var array |
||
32 | * @since 2.7 |
||
33 | */ |
||
34 | private $providers = array(); |
||
35 | |||
36 | /** |
||
37 | * Current embed width |
||
38 | * |
||
39 | * @var int |
||
40 | * @since 2.7 |
||
41 | */ |
||
42 | private $width = 0; |
||
43 | |||
44 | /** |
||
45 | * Current embed height |
||
46 | * |
||
47 | * @var int |
||
48 | * @since 2.7 |
||
49 | */ |
||
50 | private $height = 0; |
||
51 | |||
52 | /** |
||
53 | * {@inheritdoc} |
||
54 | */ |
||
55 | public function setup() { |
||
56 | |||
57 | self::$label = __( 'oEmbed', 'pods' ); |
||
58 | } |
||
59 | |||
60 | /** |
||
61 | * {@inheritdoc} |
||
62 | */ |
||
63 | public function admin_init() { |
||
64 | |||
65 | // AJAX for Uploads |
||
66 | add_action( 'wp_ajax_oembed_update_preview', array( $this, 'admin_ajax_oembed_update_preview' ) ); |
||
67 | } |
||
68 | |||
69 | /** |
||
70 | * {@inheritdoc} |
||
71 | */ |
||
72 | public function options() { |
||
73 | |||
74 | $options = array( |
||
75 | static::$type . '_repeatable' => array( |
||
76 | 'label' => __( 'Repeatable Field', 'pods' ), |
||
77 | 'default' => 0, |
||
78 | 'type' => 'boolean', |
||
79 | 'help' => __( 'Making a field repeatable will add controls next to the field which allows users to Add/Remove/Reorder additional values. These values are saved in the database as an array, so searching and filtering by them may require further adjustments".', 'pods' ), |
||
80 | 'boolean_yes_label' => '', |
||
81 | 'dependency' => true, |
||
82 | 'developer_mode' => true, |
||
83 | ), |
||
84 | static::$type . '_width' => array( |
||
85 | 'label' => __( 'Embed Width', 'pods' ), |
||
86 | 'default' => 0, |
||
87 | 'type' => 'number', |
||
88 | 'help' => __( 'Optional width to use for this oEmbed. Leave as 0 (zero) to default to none.', 'pods' ), |
||
89 | ), |
||
90 | static::$type . '_height' => array( |
||
91 | 'label' => __( 'Embed Height', 'pods' ), |
||
92 | 'default' => 0, |
||
93 | 'type' => 'number', |
||
94 | 'help' => __( 'Optional height to use for this oEmbed. Leave as 0 (zero) to default to none.', 'pods' ), |
||
95 | ), |
||
96 | static::$type . '_show_preview' => array( |
||
97 | 'label' => __( 'Show preview', 'pods' ), |
||
98 | 'default' => 0, |
||
99 | 'type' => 'boolean', |
||
100 | ), |
||
101 | ); |
||
102 | |||
103 | // Get all unique provider host names |
||
104 | $unique_providers = array(); |
||
105 | foreach ( $this->get_providers() as $provider ) { |
||
106 | if ( ! in_array( $provider['host'], $unique_providers, true ) ) { |
||
107 | $unique_providers[] = $provider['host']; |
||
108 | } |
||
109 | } |
||
110 | sort( $unique_providers ); |
||
111 | |||
112 | // Only add the options if we have data |
||
113 | if ( ! empty( $unique_providers ) ) { |
||
114 | $options[ static::$type . '_restrict_providers' ] = array( |
||
115 | 'label' => __( 'Restrict to providers', 'pods' ), |
||
116 | 'help' => __( 'Restrict input to specific WordPress oEmbed compatible providers.', 'pods' ), |
||
117 | 'type' => 'boolean', |
||
118 | 'default' => 0, |
||
119 | 'dependency' => true, |
||
120 | ); |
||
121 | $options[ static::$type . '_enable_providers' ] = array( |
||
122 | 'label' => __( 'Select enabled providers', 'pods' ), |
||
123 | 'depends-on' => array( static::$type . '_restrict_providers' => true ), |
||
124 | 'group' => array(), |
||
125 | ); |
||
126 | // Add all the oEmbed providers |
||
127 | foreach ( $unique_providers as $provider ) { |
||
128 | $options[ static::$type . '_enable_providers' ]['group'][ static::$type . '_enabled_providers_' . tag_escape( $provider ) ] = array( |
||
129 | 'label' => $provider, |
||
130 | 'type' => 'boolean', |
||
131 | 'default' => 0, |
||
132 | ); |
||
133 | } |
||
134 | }//end if |
||
135 | |||
136 | return $options; |
||
137 | } |
||
138 | |||
139 | /** |
||
140 | * {@inheritdoc} |
||
141 | */ |
||
142 | public function schema( $options = null ) { |
||
143 | |||
144 | $schema = 'LONGTEXT'; |
||
145 | |||
146 | return $schema; |
||
147 | } |
||
148 | |||
149 | /** |
||
150 | * {@inheritdoc} |
||
151 | */ |
||
152 | public function display( $value = null, $name = null, $options = null, $pod = null, $id = null ) { |
||
0 ignored issues
–
show
|
|||
153 | |||
154 | $value = $this->pre_save( $value, $id, $name, $options, null, $pod ); |
||
155 | |||
156 | $width = (int) pods_v( static::$type . '_width', $options ); |
||
157 | $height = (int) pods_v( static::$type . '_height', $options ); |
||
158 | $args = array(); |
||
159 | if ( $width > 0 ) { |
||
160 | $args['width'] = $width; |
||
161 | } |
||
162 | if ( $height > 0 ) { |
||
163 | $args['height'] = $height; |
||
164 | } |
||
165 | |||
166 | $value = wp_oembed_get( $value, $args ); |
||
167 | |||
168 | return $value; |
||
169 | } |
||
170 | |||
171 | /** |
||
172 | * {@inheritdoc} |
||
173 | */ |
||
174 | public function input( $name, $value = null, $options = null, $pod = null, $id = null ) { |
||
175 | |||
176 | $options = (array) $options; |
||
177 | $form_field_type = PodsForm::$field_type; |
||
178 | |||
179 | if ( is_array( $value ) ) { |
||
180 | $value = implode( ' ', $value ); |
||
181 | } |
||
182 | |||
183 | if ( isset( $options['name'] ) && false === PodsForm::permission( static::$type, $options['name'], $options, null, $pod, $id ) ) { |
||
184 | if ( pods_v( 'read_only', $options, false ) ) { |
||
185 | $options['readonly'] = true; |
||
186 | } else { |
||
187 | return; |
||
188 | } |
||
189 | } elseif ( ! pods_has_permissions( $options ) && pods_v( 'read_only', $options, false ) ) { |
||
190 | $options['readonly'] = true; |
||
191 | } |
||
192 | |||
193 | pods_view( PODS_DIR . 'ui/fields/oembed.php', compact( array_keys( get_defined_vars() ) ) ); |
||
194 | } |
||
195 | |||
196 | /** |
||
197 | * {@inheritdoc} |
||
198 | */ |
||
199 | public function validate( $value, $name = null, $options = null, $fields = null, $pod = null, $id = null, $params = null ) { |
||
200 | |||
201 | $errors = array(); |
||
202 | |||
203 | $check = $this->pre_save( $value, $id, $name, $options, $fields, $pod, $params ); |
||
204 | |||
205 | if ( is_array( $check ) ) { |
||
206 | $errors = $check; |
||
207 | } else { |
||
208 | if ( 0 < strlen( $value ) && '' === $check ) { |
||
209 | if ( 1 === (int) pods_v( 'required', $options ) ) { |
||
210 | $errors[] = __( 'This field is required.', 'pods' ); |
||
211 | } |
||
212 | } |
||
213 | } |
||
214 | |||
215 | if ( ! empty( $errors ) ) { |
||
216 | return $errors; |
||
0 ignored issues
–
show
The return type of
return $errors; (array ) is incompatible with the return type of the parent method PodsField::validate of type boolean .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function ![]() |
|||
217 | } |
||
218 | |||
219 | return true; |
||
220 | } |
||
221 | |||
222 | /** |
||
223 | * {@inheritdoc} |
||
224 | */ |
||
225 | public function pre_save( $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) { |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a ![]() |
|||
226 | |||
227 | $value = $this->strip_html( $value, $options ); |
||
228 | |||
229 | // Only allow ONE URL |
||
230 | if ( ! empty( $value ) ) { |
||
231 | $value = explode( ' ', $value ); |
||
232 | $value = esc_url( $value[0] ); |
||
233 | } |
||
234 | |||
235 | if ( $this->validate_provider( $value, $options ) ) { |
||
236 | return $value; |
||
237 | } else { |
||
238 | return false; |
||
239 | } |
||
240 | |||
241 | } |
||
242 | |||
243 | /** |
||
244 | * {@inheritdoc} |
||
245 | */ |
||
246 | public function ui( $id, $value, $name = null, $options = null, $fields = null, $pod = null ) { |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a ![]() |
|||
247 | |||
248 | $value = $this->pre_save( $value, $id, $name, $options, $fields, $pod ); |
||
249 | |||
250 | return $value; |
||
251 | } |
||
252 | |||
253 | /** |
||
254 | * {@inheritdoc} |
||
255 | */ |
||
256 | public function strip_html( $value, $options = null ) { |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a ![]() |
|||
257 | |||
258 | if ( is_array( $value ) ) { |
||
259 | // @codingStandardsIgnoreLine |
||
260 | $value = @implode( ' ', $value ); |
||
261 | } |
||
262 | |||
263 | $value = trim( $value ); |
||
264 | |||
265 | if ( empty( $value ) ) { |
||
266 | return $value; |
||
267 | } |
||
268 | |||
269 | // Strip HTML |
||
270 | $value = strip_tags( $value ); |
||
271 | |||
272 | // Strip shortcodes |
||
273 | $value = strip_shortcodes( $value ); |
||
274 | |||
275 | return $value; |
||
276 | } |
||
277 | |||
278 | /** |
||
279 | * Passes any unlinked URLs that are on their own line to {@link WP_Embed::shortcode()} for potential embedding. |
||
280 | * |
||
281 | * @see WP_Embed::autoembed() |
||
282 | * @see WP_Embed::autoembed_callback() |
||
283 | * |
||
284 | * @uses PodsField_OEmbed::autoembed_callback() |
||
285 | * |
||
286 | * @param string $content The content to be searched. |
||
287 | * |
||
288 | * @return string Potentially modified $content. |
||
289 | * |
||
290 | * @since 2.7 |
||
291 | */ |
||
292 | public function autoembed( $content ) { |
||
293 | |||
294 | // Replace line breaks from all HTML elements with placeholders. |
||
295 | $content = wp_replace_in_html_tags( $content, array( "\n" => '<!-- wp-line-break -->' ) ); |
||
296 | |||
297 | // Find URLs that are on their own line. |
||
298 | $content = preg_replace_callback( |
||
299 | '|^(\s*)(https?://[^\s"]+)(\s*)$|im', array( |
||
300 | $this, |
||
301 | 'autoembed_callback', |
||
302 | ), $content |
||
303 | ); |
||
304 | |||
305 | // Put the line breaks back. |
||
306 | return str_replace( '<!-- wp-line-break -->', "\n", $content ); |
||
307 | |||
308 | } |
||
309 | |||
310 | /** |
||
311 | * Callback function for {@link WP_Embed::autoembed()}. |
||
312 | * |
||
313 | * @param array $match A regex match array. |
||
314 | * |
||
315 | * @return string The embed shortcode |
||
316 | * |
||
317 | * @since 2.7 |
||
318 | */ |
||
319 | public function autoembed_callback( $match ) { |
||
320 | |||
321 | $shortcode = '[embed width="' . $this->width . '" height="' . $this->height . '"]' . $match[2] . '[/embed]'; |
||
322 | |||
323 | return $shortcode; |
||
324 | |||
325 | } |
||
326 | |||
327 | /** |
||
328 | * Get a list of available providers from the WP_oEmbed class |
||
329 | * |
||
330 | * @see wp-includes/class-oembed.php |
||
331 | * @return array $providers { |
||
332 | * Array of provider data with regex as key |
||
333 | * |
||
334 | * @type string URL for this provider |
||
335 | * @type int |
||
336 | * @type string Hostname for this provider |
||
337 | * } |
||
338 | * |
||
339 | * @since 2.7 |
||
340 | */ |
||
341 | public function get_providers() { |
||
342 | |||
343 | // Return class property if already set |
||
344 | if ( ! empty( $this->providers ) ) { |
||
345 | return $this->providers; |
||
346 | } |
||
347 | |||
348 | if ( file_exists( ABSPATH . WPINC . '/class-oembed.php' ) ) { |
||
349 | require_once ABSPATH . WPINC . '/class-oembed.php'; |
||
350 | } |
||
351 | |||
352 | // Return an empty array if no providers could be found |
||
353 | $providers = array(); |
||
354 | |||
355 | if ( function_exists( '_wp_oembed_get_object' ) ) { |
||
356 | $wp_oembed = _wp_oembed_get_object(); |
||
357 | $providers = $wp_oembed->providers; |
||
358 | |||
359 | foreach ( $providers as $key => $provider ) { |
||
360 | $url = wp_parse_url( $provider[0] ); |
||
361 | $host = $url['host']; |
||
362 | $tmp = explode( '.', $host ); |
||
363 | |||
364 | if ( count( $tmp ) === 3 ) { |
||
0 ignored issues
–
show
|
|||
365 | // Take domain names like .co.uk in consideration |
||
366 | if ( ! in_array( 'co', $tmp, true ) ) { |
||
367 | unset( $tmp[0] ); |
||
368 | } |
||
369 | } elseif ( count( $tmp ) === 4 ) { |
||
0 ignored issues
–
show
|
|||
370 | // Take domain names like .co.uk in consideration |
||
371 | unset( $tmp[0] ); |
||
372 | } |
||
373 | |||
374 | $host = implode( '.', $tmp ); |
||
375 | |||
376 | $providers[ $key ]['host'] = $host; |
||
377 | } |
||
378 | |||
379 | $this->providers = $providers; |
||
380 | }//end if |
||
381 | |||
382 | return $providers; |
||
383 | |||
384 | } |
||
385 | |||
386 | /** |
||
387 | * Takes a URL and returns the corresponding oEmbed provider's URL, if there is one. |
||
388 | * This function is ripped from WP since Pods has support from 3.8 and in the WP core this function is 4.0+ |
||
389 | * We've stripped the autodiscover part from this function to keep it basic |
||
390 | * |
||
391 | * @since 2.7 |
||
392 | * @access public |
||
393 | * |
||
394 | * @see WP_oEmbed::get_provider() |
||
395 | * |
||
396 | * @param string $url The URL to the content. |
||
397 | * |
||
398 | * @return false|string False on failure, otherwise the oEmbed provider URL. |
||
0 ignored issues
–
show
|
|||
399 | */ |
||
400 | public function get_provider( $url ) { |
||
401 | |||
402 | $provider = false; |
||
403 | |||
404 | foreach ( $this->providers as $matchmask => $data ) { |
||
405 | if ( isset( $data['host'] ) ) { |
||
406 | unset( $data['host'] ); |
||
407 | } |
||
408 | reset( $data ); |
||
409 | |||
410 | list( $providerurl, $regex ) = $data; |
||
411 | |||
412 | $match = $matchmask; |
||
413 | |||
414 | // Turn the asterisk-type provider URLs into regex |
||
415 | if ( ! $regex ) { |
||
416 | $matchmask = '#' . str_replace( '___wildcard___', '(.+)', preg_quote( str_replace( '*', '___wildcard___', $matchmask ), '#' ) ) . '#i'; |
||
417 | $matchmask = preg_replace( '|^#http\\\://|', '#https?\://', $matchmask ); |
||
418 | } |
||
419 | |||
420 | if ( preg_match( $matchmask, $url ) ) { |
||
421 | $provider = $match; |
||
422 | |||
423 | break; |
||
424 | } |
||
425 | }//end foreach |
||
426 | |||
427 | return $provider; |
||
428 | } |
||
429 | |||
430 | /** |
||
431 | * Validate a value with the enabled oEmbed providers (if required). |
||
432 | * |
||
433 | * @since 2.7 |
||
434 | * |
||
435 | * @param string $value Field value. |
||
436 | * @param array $options Field options. |
||
437 | * |
||
438 | * @return bool |
||
439 | */ |
||
440 | public function validate_provider( $value, $options ) { |
||
441 | |||
442 | // Check if we need to validate. |
||
443 | if ( 0 === (int) pods_v( static::$type . '_restrict_providers', $options ) ) { |
||
444 | return true; |
||
445 | } |
||
446 | |||
447 | $providers = $this->get_providers(); |
||
448 | |||
449 | // Filter existing providers. |
||
450 | foreach ( $providers as $key => $provider ) { |
||
451 | $fieldname = static::$type . '_enabled_providers_' . tag_escape( $provider['host'] ); |
||
452 | |||
453 | /** |
||
454 | * @todo Future compat to enable serialised strings as field options |
||
455 | */ |
||
456 | |||
457 | /** |
||
458 | * Current solution: all separate field options. |
||
459 | */ |
||
460 | if ( empty( $options[ $fieldname ] ) ) { |
||
461 | unset( $providers[ $key ] ); |
||
462 | } |
||
463 | } |
||
464 | |||
465 | // Value validation. |
||
466 | $provider_match = $this->get_provider( $value ); |
||
467 | |||
468 | foreach ( $providers as $match => $provider ) { |
||
469 | if ( $provider_match === $match ) { |
||
470 | return true; |
||
471 | } |
||
472 | } |
||
473 | |||
474 | return false; |
||
475 | } |
||
476 | |||
477 | /** |
||
478 | * Handle update preview AJAX. |
||
479 | * |
||
480 | * @since 2.7 |
||
481 | */ |
||
482 | public function admin_ajax_oembed_update_preview() { |
||
483 | |||
484 | // Sanitize input. |
||
485 | // @codingStandardsIgnoreLine |
||
486 | $params = pods_unslash( (array) $_POST ); |
||
487 | |||
488 | if ( ! empty( $params['_nonce_pods_oembed'] ) && ! empty( $params['pods_field_oembed_value'] ) && wp_verify_nonce( $params['_nonce_pods_oembed'], 'pods_field_oembed_preview' ) ) { |
||
489 | $value = $this->strip_html( $params['pods_field_oembed_value'] ); |
||
490 | |||
491 | $name = ''; |
||
492 | $options = array(); |
||
493 | |||
494 | if ( ! empty( $params['pods_field_oembed_name'] ) ) { |
||
495 | $name = $this->strip_html( $params['pods_field_oembed_name'] ); |
||
496 | } |
||
497 | |||
498 | if ( ! empty( $params['pods_field_oembed_options'] ) ) { |
||
499 | $options = $params['pods_field_oembed_options']; |
||
500 | } |
||
501 | |||
502 | // Load the field to get it's options. |
||
503 | $options = pods_api()->load_field( (object) $options ); |
||
504 | |||
505 | // Field options are stored here, if not, just stay with the full options array. |
||
506 | if ( ! empty( $options['options'] ) ) { |
||
507 | $options = $options['options']; |
||
508 | } |
||
509 | |||
510 | // Run display function to run oEmbed. |
||
511 | $value = $this->display( $value, $name, $options ); |
||
512 | |||
513 | if ( empty( $value ) ) { |
||
514 | $value = __( 'Please choose a valid oEmbed URL.', 'pods' ); |
||
515 | wp_send_json_error( $value ); |
||
516 | } else { |
||
517 | wp_send_json_success( $value ); |
||
518 | } |
||
519 | }//end if |
||
520 | wp_send_json_error( __( 'Unauthorized request', 'pods' ) ); |
||
521 | |||
522 | die(); |
||
523 | // Kill it! |
||
524 | } |
||
525 | |||
526 | } |
||
527 |
Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a
@return
annotation as described here.