1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Extension of the SimplePie_Locator class, to detect podcast feeds |
4
|
|
|
* |
5
|
|
|
* @package jetpack |
6
|
|
|
*/ |
7
|
|
|
|
8
|
|
|
/** |
9
|
|
|
* Class Jetpack_Podcast_Feed_Locator |
10
|
|
|
*/ |
11
|
|
|
class Jetpack_Podcast_Feed_Locator extends SimplePie_Locator { |
12
|
|
|
/** |
13
|
|
|
* Overrides the locator is_feed function to check for |
14
|
|
|
* appropriate podcast elements. |
15
|
|
|
* |
16
|
|
|
* @param SimplePie_File $file The file being checked. |
17
|
|
|
* @param boolean $check_html Adds text/html to the mimetypes checked. |
18
|
|
|
*/ |
19
|
|
|
public function is_feed( $file, $check_html = false ) { |
20
|
|
|
return parent::is_feed( $file, $check_html ) && $this->is_podcast_feed( $file ); |
21
|
|
|
} |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* Checks the contents of the file for elements that make |
25
|
|
|
* it a podcast feed. |
26
|
|
|
* |
27
|
|
|
* @param SimplePie_File $file The file being checked. |
28
|
|
|
*/ |
29
|
|
|
private function is_podcast_feed( $file ) { |
30
|
|
|
// If we can't read the DOM assume it's a podcast feed, we'll work |
31
|
|
|
// it out later. |
32
|
|
|
if ( ! class_exists( 'DOMDocument' ) ) { |
33
|
|
|
return true; |
34
|
|
|
} |
35
|
|
|
|
36
|
|
|
$feed_dom = $this->safely_load_xml( $file->body ); |
|
|
|
|
37
|
|
|
|
38
|
|
|
// Do this as either/or but prioritise the itunes namespace. It's pretty likely |
39
|
|
|
// that it's a podcast feed we've found if that namespace is present. |
40
|
|
|
return $feed_dom && ( $this->has_itunes_ns( $feed_dom ) || $this->has_audio_enclosures( $feed_dom ) ); |
41
|
|
|
} |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* Safely loads an XML file |
45
|
|
|
* |
46
|
|
|
* @param string $xml A string of XML to load. |
47
|
|
|
* @return DOMDocument|false A restulting DOM document or `false` if there is an error. |
48
|
|
|
*/ |
49
|
|
|
private function safely_load_xml( $xml ) { |
50
|
|
|
$disable_entity_loader = PHP_VERSION_ID < 80000; |
51
|
|
|
|
52
|
|
|
if ( $disable_entity_loader && ! function_exists( 'libxml_disable_entity_loader' ) ) { |
53
|
|
|
return false; |
54
|
|
|
} |
55
|
|
|
|
56
|
|
|
if ( $disable_entity_loader ) { |
57
|
|
|
// This function has been deprecated in PHP 8.0 because in libxml 2.9.0, external entity loading |
58
|
|
|
// is disabled by default, so this function is no longer needed to protect against XXE attacks. |
59
|
|
|
// phpcs:ignore Generic.PHP.DeprecatedFunctions.Deprecated, PHPCompatibility.FunctionUse.RemovedFunctions.libxml_disable_entity_loaderDeprecated |
60
|
|
|
$loader = libxml_disable_entity_loader( true ); |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
$errors = libxml_use_internal_errors( true ); |
64
|
|
|
|
65
|
|
|
$return = new DOMDocument(); |
66
|
|
|
if ( ! $return->loadXML( $xml ) ) { |
67
|
|
|
return false; |
68
|
|
|
} |
69
|
|
|
|
70
|
|
|
libxml_use_internal_errors( $errors ); |
71
|
|
|
|
72
|
|
|
if ( $disable_entity_loader && isset( $loader ) ) { |
73
|
|
|
// phpcs:ignore Generic.PHP.DeprecatedFunctions.Deprecated, PHPCompatibility.FunctionUse.RemovedFunctions.libxml_disable_entity_loaderDeprecated |
74
|
|
|
libxml_disable_entity_loader( $loader ); |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
return $return; |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* Checks the RSS feed for the presence of the itunes podcast namespace. |
82
|
|
|
* It's pretty loose and just checks the URI for itunes.com |
83
|
|
|
* |
84
|
|
|
* @param DOMDocument $dom The XML document to check. |
85
|
|
|
* @return boolean Whether the itunes namespace is defined. |
86
|
|
|
*/ |
87
|
|
|
private function has_itunes_ns( $dom ) { |
88
|
|
|
$xpath = new DOMXPath( $dom ); |
89
|
|
|
foreach ( $xpath->query( 'namespace::*' ) as $node ) { |
90
|
|
|
// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase |
91
|
|
|
// nodeValue is not valid, but it's part of the DOM API that we don't control. |
92
|
|
|
if ( strstr( $node->nodeValue, 'itunes.com' ) ) { |
93
|
|
|
return true; |
94
|
|
|
} |
95
|
|
|
// phpcs:enable |
96
|
|
|
} |
97
|
|
|
return false; |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* Checks the RSS feed for the presence of enclosures with an audio mimetype. |
102
|
|
|
* |
103
|
|
|
* @param DOMDocument $dom The XML document to check. |
104
|
|
|
* @return boolean Whether enclosures were found. |
105
|
|
|
*/ |
106
|
|
|
private function has_audio_enclosures( $dom ) { |
107
|
|
|
$xpath = new DOMXPath( $dom ); |
108
|
|
|
$enclosures = $xpath->query( "//enclosure[starts-with(@type,'audio/')]" ); |
109
|
|
|
return ! $enclosures ? false : $enclosures->length > 0; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
|
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.
If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.