PageRenderTime 27ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/server/wordpress/wp-content/plugins/wordpress-seo/inc/class-wpseo-image-utils.php

https://gitlab.com/suporte.spturis/carnaval2015.spturis.com.br
PHP | 485 lines | 192 code | 69 blank | 224 comment | 33 complexity | c47f857268cf230cd1c8e8c67ebc51e1 MD5 | raw file
  1. <?php
  2. /**
  3. * WPSEO plugin file.
  4. *
  5. * @package WPSEO
  6. */
  7. /**
  8. * WPSEO_Image_Utils.
  9. */
  10. class WPSEO_Image_Utils {
  11. /**
  12. * Find an attachment ID for a given URL.
  13. *
  14. * @param string $url The URL to find the attachment for.
  15. *
  16. * @return int The found attachment ID, or 0 if none was found.
  17. */
  18. public static function get_attachment_by_url( $url ) {
  19. /*
  20. * As get_attachment_by_url won't work on resized versions of images,
  21. * we strip out the size part of an image URL.
  22. */
  23. $url = preg_replace( '/(.*)-\d+x\d+\.(jpg|png|gif)$/', '$1.$2', $url );
  24. static $uploads;
  25. if ( $uploads === null ) {
  26. $uploads = wp_get_upload_dir();
  27. }
  28. // Don't try to do this for external URLs.
  29. if ( strpos( $url, $uploads['baseurl'] ) !== 0 ) {
  30. return 0;
  31. }
  32. if ( function_exists( 'wpcom_vip_attachment_url_to_postid' ) ) {
  33. // @codeCoverageIgnoreStart -- We can't test this properly.
  34. return (int) wpcom_vip_attachment_url_to_postid( $url );
  35. // @codeCoverageIgnoreEnd -- The rest we _can_ test.
  36. }
  37. return self::attachment_url_to_postid( $url );
  38. }
  39. /**
  40. * Implements the attachment_url_to_postid with use of WP Cache.
  41. *
  42. * @param string $url The attachment URL for which we want to know the Post ID.
  43. *
  44. * @return int The Post ID belonging to the attachment, 0 if not found.
  45. */
  46. protected static function attachment_url_to_postid( $url ) {
  47. $cache_key = sprintf( 'yoast_attachment_url_post_id_%s', md5( $url ) );
  48. // Set the ID based on the hashed URL in the cache.
  49. $id = wp_cache_get( $cache_key );
  50. if ( $id === 'not_found' ) {
  51. return 0;
  52. }
  53. // ID is found in cache, return.
  54. if ( $id !== false ) {
  55. return $id;
  56. }
  57. // Note: We use the WP COM version if we can, see above.
  58. $id = attachment_url_to_postid( $url );
  59. if ( empty( $id ) ) {
  60. wp_cache_set( $cache_key, 'not_found', '', ( 12 * HOUR_IN_SECONDS + wp_rand( 0, ( 4 * HOUR_IN_SECONDS ) ) ) );
  61. return 0;
  62. }
  63. // We have the Post ID, but it's not in the cache yet. We do that here and return.
  64. wp_cache_set( $cache_key, $id, '', ( 24 * HOUR_IN_SECONDS + wp_rand( 0, ( 12 * HOUR_IN_SECONDS ) ) ) );
  65. return $id;
  66. }
  67. /**
  68. * Retrieves the image data.
  69. *
  70. * @param array $image Image array with URL and metadata.
  71. * @param int $attachment_id Attachment ID.
  72. *
  73. * @return false|array {
  74. * Array of image data
  75. *
  76. * @type string $alt Image's alt text.
  77. * @type string $path Path of image.
  78. * @type int $width Width of image.
  79. * @type int $height Height of image.
  80. * @type string $type Image's MIME type.
  81. * @type string $size Image's size.
  82. * @type string $url Image's URL.
  83. * @type int $filesize The file size in bytes, if already set.
  84. * }
  85. */
  86. public static function get_data( $image, $attachment_id ) {
  87. if ( ! is_array( $image ) ) {
  88. return false;
  89. }
  90. // Deals with non-set keys and values being null or false.
  91. if ( empty( $image['width'] ) || empty( $image['height'] ) ) {
  92. return false;
  93. }
  94. $image['id'] = $attachment_id;
  95. $image['alt'] = self::get_alt_tag( $attachment_id );
  96. $image['pixels'] = ( (int) $image['width'] * (int) $image['height'] );
  97. if ( ! isset( $image['type'] ) ) {
  98. $image['type'] = get_post_mime_type( $attachment_id );
  99. }
  100. /**
  101. * Filter: 'wpseo_image_data' - Filter image data.
  102. *
  103. * Elements with keys not listed in the section will be discarded.
  104. *
  105. * @api array {
  106. * Array of image data
  107. *
  108. * @type int id Image's ID as an attachment.
  109. * @type string alt Image's alt text.
  110. * @type string path Image's path.
  111. * @type int width Width of image.
  112. * @type int height Height of image.
  113. * @type int pixels Number of pixels in the image.
  114. * @type string type Image's MIME type.
  115. * @type string size Image's size.
  116. * @type string url Image's URL.
  117. * @type int filesize The file size in bytes, if already set.
  118. * }
  119. * @api int Attachment ID.
  120. */
  121. $image = apply_filters( 'wpseo_image_data', $image, $attachment_id );
  122. // Keep only the keys we need, and nothing else.
  123. return array_intersect_key( $image, array_flip( [ 'id', 'alt', 'path', 'width', 'height', 'pixels', 'type', 'size', 'url', 'filesize' ] ) );
  124. }
  125. /**
  126. * Checks a size version of an image to see if it's not too heavy.
  127. *
  128. * @param array $image Image to check the file size of.
  129. *
  130. * @return bool True when the image is within limits, false if not.
  131. */
  132. public static function has_usable_file_size( $image ) {
  133. if ( ! is_array( $image ) || $image === [] ) {
  134. return false;
  135. }
  136. /**
  137. * Filter: 'wpseo_image_image_weight_limit' - Determines what the maximum weight
  138. * (in bytes) of an image is allowed to be, default is 2 MB.
  139. *
  140. * @api int - The maximum weight (in bytes) of an image.
  141. */
  142. $max_size = apply_filters( 'wpseo_image_image_weight_limit', 2097152 );
  143. // We cannot check without a path, so assume it's fine.
  144. if ( ! isset( $image['path'] ) ) {
  145. return true;
  146. }
  147. return ( self::get_file_size( $image ) <= $max_size );
  148. }
  149. /**
  150. * Find the right version of an image based on size.
  151. *
  152. * @param int $attachment_id Attachment ID.
  153. * @param string $size Size name.
  154. *
  155. * @return array|false Returns an array with image data on success, false on failure.
  156. */
  157. public static function get_image( $attachment_id, $size ) {
  158. $image = false;
  159. if ( $size === 'full' ) {
  160. $image = self::get_full_size_image_data( $attachment_id );
  161. }
  162. if ( ! $image ) {
  163. $image = image_get_intermediate_size( $attachment_id, $size );
  164. }
  165. if ( ! $image ) {
  166. return false;
  167. }
  168. $image['size'] = $size;
  169. return self::get_data( $image, $attachment_id );
  170. }
  171. /**
  172. * Returns the image data for the full size image.
  173. *
  174. * @param int $attachment_id Attachment ID.
  175. *
  176. * @return array|false Array when there is a full size image. False if not.
  177. */
  178. protected static function get_full_size_image_data( $attachment_id ) {
  179. $image = wp_get_attachment_metadata( $attachment_id );
  180. if ( ! is_array( $image ) ) {
  181. return false;
  182. }
  183. $image['url'] = wp_get_attachment_image_url( $attachment_id, 'full' );
  184. $image['path'] = get_attached_file( $attachment_id );
  185. $image['size'] = 'full';
  186. return $image;
  187. }
  188. /**
  189. * Finds the full file path for a given image file.
  190. *
  191. * @param string $path The relative file path.
  192. *
  193. * @return string The full file path.
  194. */
  195. public static function get_absolute_path( $path ) {
  196. static $uploads;
  197. if ( $uploads === null ) {
  198. $uploads = wp_get_upload_dir();
  199. }
  200. // Add the uploads basedir if the path does not start with it.
  201. if ( empty( $uploads['error'] ) && strpos( $path, $uploads['basedir'] ) !== 0 ) {
  202. return $uploads['basedir'] . DIRECTORY_SEPARATOR . ltrim( $path, DIRECTORY_SEPARATOR );
  203. }
  204. return $path;
  205. }
  206. /**
  207. * Get the relative path of the image.
  208. *
  209. * @param string $img Image URL.
  210. *
  211. * @return string The expanded image URL.
  212. */
  213. public static function get_relative_path( $img ) {
  214. if ( $img[0] !== '/' ) {
  215. return $img;
  216. }
  217. // If it's a relative URL, it's relative to the domain, not necessarily to the WordPress install, we
  218. // want to preserve domain name and URL scheme (http / https) though.
  219. $parsed_url = wp_parse_url( home_url() );
  220. $img = $parsed_url['scheme'] . '://' . $parsed_url['host'] . $img;
  221. return $img;
  222. }
  223. /**
  224. * Get the image file size.
  225. *
  226. * @param array $image An image array object.
  227. *
  228. * @return int The file size in bytes.
  229. */
  230. public static function get_file_size( $image ) {
  231. if ( isset( $image['filesize'] ) ) {
  232. return $image['filesize'];
  233. }
  234. // If the file size for the file is over our limit, we're going to go for a smaller version.
  235. // @todo Save the filesize to the image metadata.
  236. // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- If file size doesn't properly return, we'll not fail.
  237. return @filesize( self::get_absolute_path( $image['path'] ) );
  238. }
  239. /**
  240. * Returns the different image variations for consideration.
  241. *
  242. * @param int $attachment_id The attachment to return the variations for.
  243. *
  244. * @return array The different variations possible for this attachment ID.
  245. */
  246. public static function get_variations( $attachment_id ) {
  247. $variations = [];
  248. foreach ( self::get_sizes() as $size ) {
  249. $variation = self::get_image( $attachment_id, $size );
  250. // The get_image function returns false if the size doesn't exist for this attachment.
  251. if ( $variation ) {
  252. $variations[] = $variation;
  253. }
  254. }
  255. return $variations;
  256. }
  257. /**
  258. * Check original size of image. If original image is too small, return false, else return true.
  259. *
  260. * Filters a list of variations by a certain set of usable dimensions.
  261. *
  262. * @param array $usable_dimensions {
  263. * The parameters to check against.
  264. *
  265. * @type int $min_width Minimum width of image.
  266. * @type int $max_width Maximum width of image.
  267. * @type int $min_height Minimum height of image.
  268. * @type int $max_height Maximum height of image.
  269. * }
  270. * @param array $variations The variations that should be considered.
  271. *
  272. * @return array Whether a variation is fit for display or not.
  273. */
  274. public static function filter_usable_dimensions( $usable_dimensions, $variations ) {
  275. $filtered = [];
  276. foreach ( $variations as $variation ) {
  277. $dimensions = $variation;
  278. if ( self::has_usable_dimensions( $dimensions, $usable_dimensions ) ) {
  279. $filtered[] = $variation;
  280. }
  281. }
  282. return $filtered;
  283. }
  284. /**
  285. * Filters a list of variations by (disk) file size.
  286. *
  287. * @param array $variations The variations to consider.
  288. *
  289. * @return array The validations that pass the required file size limits.
  290. */
  291. public static function filter_usable_file_size( $variations ) {
  292. foreach ( $variations as $variation ) {
  293. // We return early to prevent measuring the file size of all the variations.
  294. if ( self::has_usable_file_size( $variation ) ) {
  295. return [ $variation ];
  296. }
  297. }
  298. return [];
  299. }
  300. /**
  301. * Retrieve the internal WP image file sizes.
  302. *
  303. * @return array An array of image sizes.
  304. */
  305. public static function get_sizes() {
  306. /**
  307. * Filter: 'wpseo_image_sizes' - Determines which image sizes we'll loop through to get an appropriate image.
  308. *
  309. * @api array - The array of image sizes to loop through.
  310. */
  311. return apply_filters( 'wpseo_image_sizes', [ 'full', 'large', 'medium_large' ] );
  312. }
  313. /**
  314. * Grabs an image alt text.
  315. *
  316. * @param int $attachment_id The attachment ID.
  317. *
  318. * @return string The image alt text.
  319. */
  320. public static function get_alt_tag( $attachment_id ) {
  321. return (string) get_post_meta( $attachment_id, '_wp_attachment_image_alt', true );
  322. }
  323. /**
  324. * Checks whether an img sizes up to the parameters.
  325. *
  326. * @param array $dimensions The image values.
  327. * @param array $usable_dimensions The parameters to check against.
  328. *
  329. * @return bool True if the image has usable measurements, false if not.
  330. */
  331. private static function has_usable_dimensions( $dimensions, $usable_dimensions ) {
  332. foreach ( [ 'width', 'height' ] as $param ) {
  333. $minimum = $usable_dimensions[ 'min_' . $param ];
  334. $maximum = $usable_dimensions[ 'max_' . $param ];
  335. $current = $dimensions[ $param ];
  336. if ( ( $current < $minimum ) || ( $current > $maximum ) ) {
  337. return false;
  338. }
  339. }
  340. return true;
  341. }
  342. /**
  343. * Gets the post's first usable content image. Null if none is available.
  344. *
  345. * @param int|null $post_id The post id.
  346. *
  347. * @return string|null The image URL.
  348. */
  349. public static function get_first_usable_content_image_for_post( $post_id = null ) {
  350. $post = get_post( $post_id );
  351. // We know get_post() returns the post or null.
  352. if ( ! $post ) {
  353. return null;
  354. }
  355. $image_finder = new WPSEO_Content_Images();
  356. $images = $image_finder->get_images( $post->ID, $post );
  357. return self::get_first_image( $images );
  358. }
  359. /**
  360. * Gets the term's first usable content image. Null if none is available.
  361. *
  362. * @param int $term_id The term id.
  363. *
  364. * @return string|null The image URL.
  365. */
  366. public static function get_first_content_image_for_term( $term_id ) {
  367. $term_description = term_description( $term_id );
  368. // We know term_description() returns a string which may be empty.
  369. if ( $term_description === '' ) {
  370. return null;
  371. }
  372. $image_finder = new WPSEO_Content_Images();
  373. $images = $image_finder->get_images_from_content( $term_description );
  374. return self::get_first_image( $images );
  375. }
  376. /**
  377. * Retrieves an attachment ID for an image uploaded in the settings.
  378. *
  379. * Due to self::get_attachment_by_url returning 0 instead of false.
  380. * 0 is also a possibility when no ID is available.
  381. *
  382. * @param string $setting The setting the image is stored in.
  383. *
  384. * @return int|bool The attachment id, or false or 0 if no ID is available.
  385. */
  386. public static function get_attachment_id_from_settings( $setting ) {
  387. $image_id = WPSEO_Options::get( $setting . '_id', false );
  388. if ( ! $image_id ) {
  389. $image = WPSEO_Options::get( $setting, false );
  390. if ( $image ) {
  391. // There is not an option to put a URL in an image field in the settings anymore, only to upload it through the media manager.
  392. // This means an attachment always exists, so doing this is only needed once.
  393. $image_id = self::get_attachment_by_url( $image );
  394. WPSEO_Options::set( $setting . '_id', $image_id );
  395. }
  396. }
  397. return $image_id;
  398. }
  399. /**
  400. * Retrieves the first possible image url from an array of images.
  401. *
  402. * @param array $images The array to extract image url from.
  403. *
  404. * @return string|null The extracted image url when found, null when not found.
  405. */
  406. protected static function get_first_image( $images ) {
  407. if ( ! is_array( $images ) ) {
  408. return null;
  409. }
  410. $images = array_filter( $images );
  411. if ( empty( $images ) ) {
  412. return null;
  413. }
  414. return reset( $images );
  415. }
  416. }