api
3 months ago
backups
3 months ago
cache
3 months ago
cli
3 months ago
directory
3 months ago
external
3 months ago
integrations
3 months ago
lazy-load
3 months ago
media
3 months ago
media-library
3 months ago
membership
3 months ago
modules
3 months ago
parser
3 months ago
photon
3 months ago
resize
3 months ago
security
3 months ago
smush
3 months ago
srcset
3 months ago
stats
3 months ago
threads
3 months ago
transform
3 months ago
class-animated-status-controller.php
3 months ago
class-array-utils.php
3 months ago
class-attachment-id-list.php
3 months ago
class-backup-size.php
3 months ago
class-configs.php
3 months ago
class-controller.php
3 months ago
class-core.php
3 months ago
class-cron-controller.php
3 months ago
class-deprecated-hooks.php
3 months ago
class-error-handler.php
3 months ago
class-file-system.php
3 months ago
class-file-utils.php
3 months ago
class-format-utils.php
3 months ago
class-helper.php
3 months ago
class-hub-connector.php
3 months ago
class-installer.php
3 months ago
class-keyword-exclusions.php
3 months ago
class-modules.php
3 months ago
class-optimization-controller.php
3 months ago
class-plugin-settings-watcher.php
3 months ago
class-product-analytics.php
3 months ago
class-rest.php
3 months ago
class-server-utils.php
3 months ago
class-settings.php
3 months ago
class-shim.php
3 months ago
class-smush-file.php
3 months ago
class-stats.php
3 months ago
class-time-utils.php
3 months ago
class-timer.php
3 months ago
class-upload-dir.php
3 months ago
class-url-utils.php
3 months ago
class-wp-query-utils.php
3 months ago
wp-compat.php
3 months ago
class-url-utils.php
285 lines
| 1 | <?php |
| 2 | |
| 3 | namespace Smush\Core; |
| 4 | |
| 5 | use Smush\Core\CDN\CDN_Helper; |
| 6 | use Smush\Core\Transform\Transformation_Controller; |
| 7 | |
| 8 | class Url_Utils { |
| 9 | /** |
| 10 | * @var Upload_Dir |
| 11 | */ |
| 12 | private $upload_dir; |
| 13 | |
| 14 | /** |
| 15 | * @var string |
| 16 | */ |
| 17 | private $content_url; |
| 18 | |
| 19 | public function __construct() { |
| 20 | $this->upload_dir = new Upload_Dir(); |
| 21 | } |
| 22 | |
| 23 | public function get_extension( $url ) { |
| 24 | $path = wp_parse_url( $url, PHP_URL_PATH ); |
| 25 | if ( empty( $path ) ) { |
| 26 | return false; |
| 27 | } |
| 28 | |
| 29 | return strtolower( pathinfo( $path, PATHINFO_EXTENSION ) ); |
| 30 | } |
| 31 | |
| 32 | public function get_url_scheme( $url ) { |
| 33 | $url_parts = wp_parse_url( $url ); |
| 34 | |
| 35 | return empty( $url_parts['scheme'] ) |
| 36 | ? false |
| 37 | : $url_parts['scheme']; |
| 38 | } |
| 39 | |
| 40 | /** |
| 41 | * @param $url |
| 42 | * |
| 43 | * @return string |
| 44 | * @see attachment_url_to_postid() |
| 45 | */ |
| 46 | public function make_media_url_relative( $url ) { |
| 47 | $upload_url = $this->upload_dir->get_upload_url(); |
| 48 | $path = $url; |
| 49 | |
| 50 | $site_url = parse_url( $upload_url ); |
| 51 | $image_path = parse_url( $path ); |
| 52 | |
| 53 | // Force the protocols to match if needed. |
| 54 | if ( isset( $image_path['scheme'] ) && ( $image_path['scheme'] !== $site_url['scheme'] ) ) { |
| 55 | $path = str_replace( $image_path['scheme'], $site_url['scheme'], $path ); |
| 56 | } |
| 57 | |
| 58 | if ( str_starts_with( $path, $upload_url . '/' ) ) { |
| 59 | $path = substr( $path, strlen( $upload_url . '/' ) ); |
| 60 | } |
| 61 | |
| 62 | return $path; |
| 63 | } |
| 64 | |
| 65 | public function guess_dimensions_from_image_url( $url ) { |
| 66 | $width_height_string = array(); |
| 67 | |
| 68 | if ( preg_match( '#-(\d+)x(\d+)\.(?:jpe?g|png|gif|webp|svg)#i', $url, $width_height_string ) ) { |
| 69 | $width = (int) $width_height_string[1]; |
| 70 | $height = (int) $width_height_string[2]; |
| 71 | |
| 72 | if ( $width && $height ) { |
| 73 | return array( $width, $height ); |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | return array( false, false ); |
| 78 | } |
| 79 | |
| 80 | public function get_query_vars( $url ) { |
| 81 | // Decode HTML entities in the URL. |
| 82 | $url = html_entity_decode( $url ); |
| 83 | |
| 84 | $parse_url = wp_parse_url( $url ); |
| 85 | $query_vars = array(); |
| 86 | if ( ! empty( $parse_url['query'] ) ) { |
| 87 | wp_parse_str( $parse_url['query'], $query_vars ); |
| 88 | } |
| 89 | |
| 90 | return $query_vars; |
| 91 | } |
| 92 | |
| 93 | public function get_image_dimensions( $image_url ) { |
| 94 | $dimensions = apply_filters( 'wp_smush_get_image_dimensions', false, $image_url ); |
| 95 | if ( $dimensions ) { |
| 96 | return $dimensions; |
| 97 | } |
| 98 | |
| 99 | $image_url = apply_filters( 'wp_smush_get_image_dimensions_url', $image_url ); |
| 100 | |
| 101 | return $this->_get_image_dimensions( $image_url ); |
| 102 | } |
| 103 | |
| 104 | private function _get_image_dimensions( $image_url ) { |
| 105 | $default = array( false, false ); |
| 106 | |
| 107 | if ( empty( $image_url ) ) { |
| 108 | return $default; |
| 109 | } |
| 110 | |
| 111 | list( $width, $height ) = $this->guess_dimensions_from_image_url( $image_url ); |
| 112 | |
| 113 | if ( ! empty( $width ) && ! empty( $height ) && $width > Transformation_Controller::get_min_transformable_image_dimension() ) { |
| 114 | return array( $width, $height ); |
| 115 | } |
| 116 | |
| 117 | if ( $this->is_external_url( $image_url ) ) { |
| 118 | if ( ! $this->should_fetch_external_image_dimensions( $image_url ) ) { |
| 119 | return $default; |
| 120 | } |
| 121 | |
| 122 | if ( ! $this->url_has_200_response( $image_url ) ) { |
| 123 | return $default; |
| 124 | } |
| 125 | |
| 126 | return $this->getimagesize( $image_url ); |
| 127 | } |
| 128 | |
| 129 | $local_path = $this->url_to_path( $image_url ); |
| 130 | if ( ! $local_path || ! file_exists( $local_path ) ) { |
| 131 | return $default; |
| 132 | } |
| 133 | |
| 134 | return $this->getimagesize( $local_path ); |
| 135 | } |
| 136 | |
| 137 | public function get_url_content_type_header( $image_url ) { |
| 138 | // Use url headers to check content type |
| 139 | if ( $this->is_external_url( $image_url ) ) { |
| 140 | $headers = get_headers( $image_url, 1 ); |
| 141 | |
| 142 | if ( empty( $headers['content-type'] ) ) { |
| 143 | return false; |
| 144 | } |
| 145 | |
| 146 | return $headers['content-type']; |
| 147 | } else { |
| 148 | return false; |
| 149 | } |
| 150 | } |
| 151 | |
| 152 | private function should_fetch_external_image_dimensions( $image_url ) { |
| 153 | return ini_get( 'allow_url_fopen' ) && apply_filters( 'wp_smush_should_fetch_external_image_dimensions', false, $image_url ); |
| 154 | } |
| 155 | |
| 156 | private function getimagesize( $image_url ) { |
| 157 | $sizes = wp_getimagesize( $image_url ); |
| 158 | |
| 159 | if ( empty( $sizes ) ) { |
| 160 | return array( false, false ); |
| 161 | } |
| 162 | |
| 163 | return array( $sizes[0], $sizes[1] ); |
| 164 | } |
| 165 | |
| 166 | public function url_has_200_response( $url ) { |
| 167 | if ( ! $url || ! ini_get( 'allow_url_fopen' ) ) { |
| 168 | return false; |
| 169 | } |
| 170 | |
| 171 | $file_headers = get_headers( $url ); |
| 172 | |
| 173 | if ( empty( $file_headers[0] ) ) { |
| 174 | return false; |
| 175 | } |
| 176 | |
| 177 | return false !== strstr( $file_headers[0], '200' ); |
| 178 | } |
| 179 | |
| 180 | public function is_external_url( $absolute_url ) { |
| 181 | if ( str_starts_with( $absolute_url, $this->get_content_url() ) ) { |
| 182 | return false; |
| 183 | } |
| 184 | |
| 185 | if ( str_starts_with( $absolute_url, $this->upload_dir->get_upload_url() ) ) { |
| 186 | return false; |
| 187 | } |
| 188 | |
| 189 | return true; |
| 190 | } |
| 191 | |
| 192 | public function url_to_path( $absolute_url ) { |
| 193 | if ( str_starts_with( $absolute_url, $this->get_content_url() ) ) { |
| 194 | return str_replace( $this->get_content_url(), WP_CONTENT_DIR, $absolute_url ); |
| 195 | } |
| 196 | |
| 197 | $upload_url = $this->upload_dir->get_upload_url(); |
| 198 | $upload_dir = $this->upload_dir->get_upload_path(); |
| 199 | |
| 200 | if ( str_starts_with( $absolute_url, $upload_url ) ) { |
| 201 | return str_replace( $upload_url, $upload_dir, $absolute_url ); |
| 202 | } |
| 203 | |
| 204 | return false; |
| 205 | } |
| 206 | |
| 207 | private function get_content_url() { |
| 208 | if ( ! $this->content_url ) { |
| 209 | $this->content_url = content_url(); |
| 210 | } |
| 211 | |
| 212 | return $this->content_url; |
| 213 | } |
| 214 | |
| 215 | /** |
| 216 | * Get full size image url from resized one. |
| 217 | * |
| 218 | * @param string $src Image URL. |
| 219 | * |
| 220 | * @return string |
| 221 | * @since 3.0 |
| 222 | * |
| 223 | */ |
| 224 | public function get_url_without_dimensions( $src ) { |
| 225 | $extensions = array( |
| 226 | 'gif', |
| 227 | 'jpg', |
| 228 | 'jpeg', |
| 229 | 'png', |
| 230 | 'webp', |
| 231 | ); |
| 232 | if ( ! preg_match( '/(-\d+x\d+)\.(' . implode( '|', $extensions ) . ')(?:\?.+)?$/i', $src, $src_parts ) ) { |
| 233 | return $src; |
| 234 | } |
| 235 | |
| 236 | // Remove WP's resize string to get the original image. |
| 237 | $original_src = str_replace( $src_parts[1], '', $src ); |
| 238 | |
| 239 | // Extracts the file path to the image minus the base url. |
| 240 | $file_path = substr( $original_src, strlen( $this->upload_dir->get_upload_url() ) ); |
| 241 | |
| 242 | // Continue only if the file exists. |
| 243 | if ( file_exists( $this->upload_dir->get_upload_path() . $file_path ) ) { |
| 244 | return $original_src; |
| 245 | } |
| 246 | |
| 247 | // Revert to source if file does not exist. |
| 248 | return $src; |
| 249 | } |
| 250 | |
| 251 | /** |
| 252 | * Convert original image URL to scaled image URL. |
| 253 | * |
| 254 | * @param string $src Original image URL. |
| 255 | * |
| 256 | * @return string|null |
| 257 | */ |
| 258 | public function get_scaled_image_url( $original_src ) { |
| 259 | if ( strpos( $original_src, '-scaled' ) !== false ) { |
| 260 | return $original_src; |
| 261 | } |
| 262 | |
| 263 | $path_info = pathinfo( $original_src ); |
| 264 | $scaled_filename = $path_info['filename'] . '-scaled.' . $path_info['extension']; |
| 265 | $scaled_src = str_replace( $path_info['basename'], $scaled_filename, $original_src ); |
| 266 | |
| 267 | $scaled_path = $this->url_to_path( $scaled_src ); |
| 268 | if ( $scaled_path && file_exists( $scaled_path ) ) { |
| 269 | return $scaled_src; |
| 270 | } |
| 271 | |
| 272 | return null; |
| 273 | } |
| 274 | |
| 275 | public function normalize_url( $url ) { |
| 276 | $url = str_replace( array( 'http://', 'https://', 'www.' ), '', $url ); |
| 277 | |
| 278 | return untrailingslashit( $url ); |
| 279 | } |
| 280 | |
| 281 | public function is_relative( $url ) { |
| 282 | return ! empty( preg_match( '/^\./', $url ) ) || empty( wp_parse_url( $url, PHP_URL_HOST ) ); |
| 283 | } |
| 284 | } |
| 285 |