Sin descripción

class.videopress-video.php 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. <?php
  2. /**
  3. * VideoPress video object retrieved from VideoPress servers and parsed.
  4. *
  5. * @since 1.3
  6. */
  7. class VideoPress_Video {
  8. public $version = 3;
  9. /**
  10. * Manifest version returned by remote service.
  11. *
  12. * @var string
  13. * @since 1.3
  14. */
  15. const manifest_version = '1.5';
  16. /**
  17. * Expiration of the video expressed in Unix time
  18. *
  19. * @var int
  20. * @since 1.3
  21. */
  22. public $expires;
  23. /**
  24. * VideoPress unique identifier
  25. *
  26. * @var string
  27. * @since 1.3
  28. */
  29. public $guid;
  30. /**
  31. * WordPress.com blog identifier
  32. *
  33. * @var int
  34. * @since 1.5
  35. */
  36. public $blog_id;
  37. /**
  38. * Remote blog attachment identifier
  39. *
  40. * @var int
  41. * @since 1.5
  42. */
  43. public $post_id;
  44. /**
  45. * Maximum desired width.
  46. *
  47. * @var int
  48. * @since 1.3
  49. */
  50. public $maxwidth;
  51. /**
  52. * Video width calculated based on original video dimensions and the requested maxwidth
  53. *
  54. * @var int
  55. * @since 1.3
  56. */
  57. public $calculated_width;
  58. /**
  59. * Video height calculated based on original video dimensions and the requested maxwidth
  60. *
  61. * @var int
  62. * @since 1.3
  63. */
  64. public $calculated_height;
  65. /**
  66. * Video title
  67. *
  68. * @var string
  69. * @since 1.3
  70. */
  71. public $title;
  72. /**
  73. * Video description
  74. *
  75. * @var string
  76. * @since 4.4
  77. */
  78. public $description;
  79. /**
  80. * Directionality of title text. ltr or rtl
  81. *
  82. * @var string
  83. * @since 1.3
  84. */
  85. public $text_direction;
  86. /**
  87. * Text and audio language as ISO 639-2 language code
  88. *
  89. * @var string
  90. * @since 1.3
  91. */
  92. public $language;
  93. /**
  94. * Video duration in whole seconds
  95. *
  96. * @var int
  97. * @since 1.3
  98. */
  99. public $duration;
  100. /**
  101. * Recommended minimum age of the viewer.
  102. *
  103. * @var int
  104. * @since 1.3
  105. */
  106. public $age_rating;
  107. /**
  108. * Video author has restricted video embedding or sharing
  109. *
  110. * @var bool
  111. * @since 1.3
  112. */
  113. public $restricted_embed;
  114. /**
  115. * Poster frame image URI for the given video guid and calculated dimensions.
  116. *
  117. * @var string
  118. * @since 1.3
  119. */
  120. public $poster_frame_uri;
  121. /**
  122. * Video files associated with the given guid for the calculated dimensions.
  123. *
  124. * @var stdClass
  125. * @since 1.3
  126. */
  127. public $videos;
  128. /**
  129. * Video player information
  130. *
  131. * @var stdClass
  132. * @since 1.3
  133. */
  134. public $players;
  135. /**
  136. * Video player skinning preferences including background color and watermark
  137. *
  138. * @var array
  139. * @since 1.5
  140. */
  141. public $skin;
  142. /**
  143. * Closed captions if available for the given video. Associative array of ISO 639-2 language code and a WebVTT URI
  144. *
  145. * @var array
  146. * @since 1.5
  147. */
  148. public $captions;
  149. /**
  150. * Setup the object.
  151. * Request video information from VideoPress servers and process the response.
  152. *
  153. * @since 1.3
  154. * @var string $guid VideoPress unique identifier
  155. * @var int $maxwidth maximum requested video width. final width and height are calculated on VideoPress servers based on the aspect ratio of the original video upload.
  156. */
  157. public function __construct( $guid, $maxwidth = 640 ) {
  158. $this->guid = $guid;
  159. $maxwidth = absint( $maxwidth );
  160. if ( $maxwidth > 0 ) {
  161. $this->maxwidth = $maxwidth;
  162. }
  163. $data = $this->get_data();
  164. if ( is_wp_error( $data ) || empty( $data ) ) {
  165. /** This filter is documented in modules/videopress/class.videopress-player.php */
  166. if ( ! apply_filters( 'jetpack_videopress_use_legacy_player', false ) ) {
  167. // Unlike the Flash player, the new player does it's own error checking, age gate, etc.
  168. $data = (object) array(
  169. 'guid' => $guid,
  170. 'width' => $maxwidth,
  171. 'height' => $maxwidth / 16 * 9,
  172. );
  173. } else {
  174. $this->error = $data;
  175. return;
  176. }
  177. }
  178. if ( isset( $data->blog_id ) ) {
  179. $this->blog_id = absint( $data->blog_id );
  180. }
  181. if ( isset( $data->post_id ) ) {
  182. $this->post_id = absint( $data->post_id );
  183. }
  184. if ( isset( $data->title ) && $data->title !== '' ) {
  185. $this->title = trim( str_replace( '&nbsp;', ' ', $data->title ) );
  186. }
  187. if ( isset( $data->description ) && $data->description !== '' ) {
  188. $this->description = trim( $data->description );
  189. }
  190. if ( isset( $data->text_direction ) && $data->text_direction === 'rtl' ) {
  191. $this->text_direction = 'rtl';
  192. } else {
  193. $this->text_direction = 'ltr';
  194. }
  195. if ( isset( $data->language ) ) {
  196. $this->language = $data->language;
  197. }
  198. if ( isset( $data->duration ) && $data->duration > 0 ) {
  199. $this->duration = absint( $data->duration );
  200. }
  201. if ( isset( $data->width ) && $data->width > 0 ) {
  202. $this->calculated_width = absint( $data->width );
  203. }
  204. if ( isset( $data->height ) && $data->height > 0 ) {
  205. $this->calculated_height = absint( $data->height );
  206. }
  207. if ( isset( $data->age_rating ) ) {
  208. $this->age_rating = absint( $this->age_rating );
  209. }
  210. if ( isset( $data->restricted_embed ) && $data->restricted_embed === true ) {
  211. $this->restricted_embed = true;
  212. } else {
  213. $this->restricted_embed = false;
  214. }
  215. if ( isset( $data->posterframe ) && $data->posterframe !== '' ) {
  216. $this->poster_frame_uri = esc_url_raw( $data->posterframe, array( 'http', 'https' ) );
  217. }
  218. if ( isset( $data->mp4 ) || isset( $data->ogv ) ) {
  219. $this->videos = new stdClass();
  220. if ( isset( $data->mp4 ) ) {
  221. $this->videos->mp4 = $data->mp4;
  222. }
  223. if ( isset( $data->ogv ) ) {
  224. $this->videos->ogv = $data->ogv;
  225. }
  226. }
  227. if ( isset( $data->swf ) ) {
  228. if ( ! isset( $this->players ) ) {
  229. $this->players = new stdClass();
  230. }
  231. $this->players->swf = $data->swf;
  232. }
  233. if ( isset( $data->skin ) ) {
  234. $this->skin = $data->skin;
  235. }
  236. if ( isset( $data->captions ) ) {
  237. $this->captions = (array) $data->captions;
  238. }
  239. }
  240. /**
  241. * Convert an Expires HTTP header value into Unix time for use in WP Cache
  242. *
  243. * @since 1.3
  244. * @var string $expires_header
  245. * @return int|bool Unix time or false
  246. */
  247. public static function calculate_expiration( $expires_header ) {
  248. if ( empty( $expires_header ) || ! is_string( $expires_header ) ) {
  249. return false;
  250. }
  251. if (
  252. class_exists( 'DateTimeZone' )
  253. && method_exists( 'DateTime', 'createFromFormat' )
  254. ) {
  255. $expires_date = DateTime::createFromFormat( 'D, d M Y H:i:s T', $expires_header, new DateTimeZone( 'UTC' ) );
  256. if ( $expires_date instanceof DateTime ) {
  257. return date_format( $expires_date, 'U' );
  258. }
  259. } else {
  260. $expires_array = strptime( $expires_header, '%a, %d %b %Y %H:%M:%S %Z' );
  261. if ( is_array( $expires_array ) && isset( $expires_array['tm_hour'] ) && isset( $expires_array['tm_min'] ) && isset( $expires_array['tm_sec'] ) && isset( $expires_array['tm_mon'] ) && isset( $expires_array['tm_mday'] ) && isset( $expires_array['tm_year'] ) ) {
  262. return gmmktime( $expires_array['tm_hour'], $expires_array['tm_min'], $expires_array['tm_sec'], 1 + $expires_array['tm_mon'], $expires_array['tm_mday'], 1900 + $expires_array['tm_year'] );
  263. }
  264. }
  265. return false;
  266. }
  267. /**
  268. * Extract the site's host domain for statistics and comparison against an allowed site list in the case of restricted embeds.
  269. *
  270. * @since 1.2
  271. * @param string $url absolute URL
  272. * @return bool|string host component of the URL, or false if none found
  273. */
  274. public static function hostname( $url ) {
  275. return wp_parse_url( esc_url_raw( $url ), PHP_URL_HOST );
  276. }
  277. /**
  278. * Request data from WordPress.com for the given guid, maxwidth, and calculated blog hostname.
  279. *
  280. * @since 1.3
  281. * @return stdClass|WP_Error parsed JSON response or WP_Error if request unsuccessful
  282. */
  283. private function get_data() {
  284. global $wp_version;
  285. $domain = self::hostname( home_url() );
  286. $request_params = array(
  287. 'guid' => $this->guid,
  288. 'domain' => $domain,
  289. );
  290. if ( isset( $this->maxwidth ) && $this->maxwidth > 0 ) {
  291. $request_params['maxwidth'] = $this->maxwidth;
  292. }
  293. $url = 'https://v.wordpress.com/data/wordpress.json';
  294. $response = wp_remote_get(
  295. add_query_arg( $request_params, $url ),
  296. array(
  297. 'redirection' => 1,
  298. 'user-agent' => 'VideoPress plugin ' . $this->version . '; WordPress ' . $wp_version . ' (' . home_url( '/' ) . ')',
  299. )
  300. );
  301. unset( $request_params );
  302. unset( $url );
  303. $response_body = wp_remote_retrieve_body( $response );
  304. $response_code = absint( wp_remote_retrieve_response_code( $response ) );
  305. if ( is_wp_error( $response ) ) {
  306. return $response;
  307. } elseif ( $response_code === 400 ) {
  308. return new WP_Error( 'bad_config', __( 'The VideoPress plugin could not communicate with the VideoPress servers. This error is most likely caused by a misconfigured plugin. Please reinstall or upgrade.', 'jetpack' ) );
  309. } elseif ( $response_code === 403 ) {
  310. return new WP_Error( 'http_forbidden', '<p>' . sprintf( __( '<strong>%s</strong> is not an allowed embed site.', 'jetpack' ), esc_html( $domain ) ) . '</p><p>' . __( 'Publisher limits playback of video embeds.', 'jetpack' ) . '</p>' );
  311. } elseif ( $response_code === 404 ) {
  312. return new WP_Error( 'http_not_found', '<p>' . sprintf( __( 'No data found for VideoPress identifier: <strong>%s</strong>.', 'jetpack' ), $this->guid ) . '</p>' );
  313. } elseif ( $response_code !== 200 || empty( $response_body ) ) {
  314. return;
  315. } else {
  316. $expires_header = wp_remote_retrieve_header( $response, 'Expires' );
  317. if ( ! empty( $expires_header ) ) {
  318. $expires = self::calculate_expiration( $expires_header );
  319. if ( ! empty( $expires ) ) {
  320. $this->expires = $expires;
  321. }
  322. }
  323. return json_decode( $response_body );
  324. }
  325. }
  326. }