Completed
Push — add/product-ratings-to-search ( 91683c...b05261 )
by
unknown
344:08 queued 334:42
created

Jetpack_Podcast_Feed_Locator   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 102
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
dl 0
loc 102
rs 10
c 0
b 0
f 0
wmc 18
lcom 1
cbo 2

5 Methods

Rating   Name   Duplication   Size   Complexity  
A is_feed() 0 3 2
A is_podcast_feed() 0 13 4
B safely_load_xml() 0 30 7
A has_itunes_ns() 0 12 3
A has_audio_enclosures() 0 5 2
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 );
0 ignored issues
show
Bug introduced by
The property body does not seem to exist in SimplePie_File.

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.

Loading history...
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