| @@ -60,14 +60,28 @@ | ||
| 60 | 60 | 'css' => 'text/css', |
| 61 | 61 | 'js' => 'application/javascript', |
| 62 | 62 | ); |
| 63 | 63 | |
| 64 | -/* | |
| 65 | - Constants */ | |
| 64 | +$wp_content_base = '/wp-content'; | |
| 65 | +if ( isset( $_SERVER['SCRIPT_NAME'] ) && false === strpos( $_SERVER['SCRIPT_NAME'], '/wp-content' ) ) { | |
| 66 | + $script_name = explode( '/', ltrim( $_SERVER['SCRIPT_NAME'], '/' ) ); | |
| 67 | + if ( ! empty( $script_name[0] ) ) { | |
| 68 | + $wp_content_base = '/' . $script_name[0]; | |
| 69 | + } | |
| 70 | +} | |
| 71 | + | |
| 72 | +$current_dir = file_optimizer_normalize_path( realpath( dirname( __DIR__ ) ) ); | |
| 73 | + | |
| 74 | +/* Constants */ | |
| 66 | 75 | // By default determine the document root from this scripts path in the plugins dir (you can hardcode this define) |
| 67 | -define( 'CONCAT_FILES_ROOT', substr( dirname( __DIR__ ), 0, strpos( dirname( __DIR__ ), '/wp-content' ) ) ); | |
| 68 | -define( 'POWERED_CACHE_FO_CACHE_DIR', CONCAT_FILES_ROOT . '/wp-content/cache/min/' ); | |
| 76 | +define( 'CONCAT_FILES_ROOT', substr( $current_dir, 0, strpos( $current_dir, $wp_content_base ) ) ); | |
| 77 | +define( 'POWERED_CACHE_FO_CACHE_DIR', CONCAT_FILES_ROOT . $wp_content_base.'/cache/min/' ); | |
| 78 | +define( 'POWERED_CACHE_FO_DEBUG', false ); | |
| 69 | 79 | |
| 80 | +if ( ! defined( 'POWERED_CACHE_FO_DISABLE_CACHE_HEADERS' ) ) { | |
| 81 | + define( 'POWERED_CACHE_FO_DISABLE_CACHE_HEADERS', false ); | |
| 82 | +} | |
| 83 | + | |
| 70 | 84 | if ( ! file_exists( POWERED_CACHE_FO_CACHE_DIR ) ) { |
| 71 | 85 | mkdir( POWERED_CACHE_FO_CACHE_DIR, 0775, true ); |
| 72 | 86 | } |
| 73 | 87 | |
| @@ -115,12 +129,14 @@ | ||
| 115 | 129 | } |
| 116 | 130 | |
| 117 | 131 | function concat_get_path( $uri ) { |
| 118 | 132 | if ( ! strlen( $uri ) ) { |
| 133 | + maybe_add_debug_log( sprintf( "File Optimizer 400 - could not retrieve file path for uri %s", $uri ) ); | |
| 119 | 134 | concat_http_status_exit( 400 ); |
| 120 | 135 | } |
| 121 | 136 | |
| 122 | 137 | if ( false !== strpos( $uri, '..' ) || false !== strpos( $uri, "\0" ) ) { |
| 138 | + maybe_add_debug_log( sprintf( "File Optimizer 400 - could not retrieve file path for uri %s", $uri ) ); | |
| 123 | 139 | concat_http_status_exit( 400 ); |
| 124 | 140 | } |
| 125 | 141 | |
| 126 | 142 | return CONCAT_FILES_ROOT . ( '/' != $uri[0] ? '/' : '' ) . $uri; |
| @@ -138,8 +154,9 @@ | ||
| 138 | 154 | } |
| 139 | 155 | |
| 140 | 156 | /* Main() */ |
| 141 | 157 | if ( ! in_array( $_SERVER['REQUEST_METHOD'], array( 'GET', 'HEAD' ) ) ) { |
| 158 | + maybe_add_debug_log( sprintf( "File Optimizer 400 - unsupported request method: %s", $_SERVER['REQUEST_METHOD'] ) ); | |
| 142 | 159 | concat_http_status_exit( 400 ); |
| 143 | 160 | } |
| 144 | 161 | |
| 145 | 162 | // /_static/??/foo/bar.css,/foo1/bar/baz.css?m=293847g |
| @@ -146,12 +163,14 @@ | ||
| 146 | 163 | // or |
| 147 | 164 | // /_static/??-eJzTT8vP109KLNJLLi7W0QdyDEE8IK4CiVjn2hpZGluYmKcDABRMDPM= |
| 148 | 165 | $args = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_QUERY ); |
| 149 | 166 | if ( ! $args || false === strpos( $args, '?' ) ) { |
| 167 | + maybe_add_debug_log( sprintf( "File Optimizer 400 - empty query arg or not ? exists" ) ); | |
| 150 | 168 | concat_http_status_exit( 400 ); |
| 151 | 169 | } |
| 152 | 170 | |
| 153 | 171 | $args = substr( $args, strpos( $args, '?' ) + 1 ); |
| 172 | +$args = str_replace( [ '&minify=1', '&minify=0' ], '', $args ); // remove minify parameter | |
| 154 | 173 | |
| 155 | 174 | // /foo/bar.css,/foo1/bar/baz.css?m=293847g |
| 156 | 175 | // or |
| 157 | 176 | // -eJzTT8vP109KLNJLLi7W0QdyDEE8IK4CiVjn2hpZGluYmKcDABRMDPM= |
| @@ -159,8 +178,9 @@ | ||
| 159 | 178 | $args = @gzuncompress( base64_decode( substr( $args, 1 ) ) ); |
| 160 | 179 | |
| 161 | 180 | // Invalid data, abort! |
| 162 | 181 | if ( false === $args ) { |
| 182 | + maybe_add_debug_log( sprintf( "File Optimizer 400 - Invalid Data" ) ); | |
| 163 | 183 | concat_http_status_exit( 400 ); |
| 164 | 184 | } |
| 165 | 185 | } |
| 166 | 186 | |
| @@ -172,13 +192,23 @@ | ||
| 172 | 192 | |
| 173 | 193 | // /foo/bar.css,/foo1/bar/baz.css |
| 174 | 194 | $args = explode( ',', $args ); |
| 175 | 195 | if ( ! $args ) { |
| 196 | + maybe_add_debug_log( sprintf( "File Optimizer 400 - Empty args" ) ); | |
| 176 | 197 | concat_http_status_exit( 400 ); |
| 177 | 198 | } |
| 178 | 199 | |
| 200 | +// array('/wp-content/foo/bar.css','//cdn.cname.com/wp-content/foo/bar.css') | |
| 201 | +// get real path when it masked from cdn | |
| 202 | +foreach ( $args as $index => $arg ) { | |
| 203 | + if ( 0 === stripos( $arg, '//' ) ) { | |
| 204 | + $args[ $index ] = parse_url( str_replace( '//', 'http://', $arg ), PHP_URL_PATH ); | |
| 205 | + } | |
| 206 | +} | |
| 207 | + | |
| 179 | 208 | // array( '/foo/bar.css', '/foo1/bar/baz.css' ) |
| 180 | 209 | if ( 0 == count( $args ) || count( $args ) > $concat_max_files ) { |
| 210 | + maybe_add_debug_log( sprintf( "File Optimizer 400 - Concatenating too many or zero file: %s files on queue", count( $args ) ) ); | |
| 181 | 211 | concat_http_status_exit( 400 ); |
| 182 | 212 | } |
| 183 | 213 | |
| 184 | 214 | // If we're in a subdirectory context, use that as the root. |
| @@ -194,10 +224,10 @@ | ||
| 194 | 224 | $last_modified = 0; |
| 195 | 225 | $pre_output = ''; |
| 196 | 226 | $output = ''; |
| 197 | 227 | |
| 198 | -$do_minify = (bool) stripos( $_SERVER['REQUEST_URI'], 'minify=1' ); | |
| 199 | -$hash = sha1( $_SERVER['REQUEST_URI'] ); | |
| 228 | +$do_minify = (bool) stripos( $_SERVER['REQUEST_URI'], 'minify=1' ); | |
| 229 | +$hash = sha1( $_SERVER['REQUEST_URI'] ); | |
| 200 | 230 | $latest_file = end( $args ); |
| 201 | 231 | |
| 202 | 232 | $cache_file_name = POWERED_CACHE_FO_CACHE_DIR . $hash; |
| 203 | 233 | if ( 'application/javascript' == concat_get_mtype( $latest_file ) ) { |
| @@ -210,8 +240,9 @@ | ||
| 210 | 240 | $buf = @file_get_contents( $cache_file_name ); |
| 211 | 241 | if ( $buf ) { |
| 212 | 242 | $stat = stat( $cache_file_name ); |
| 213 | 243 | |
| 244 | + set_cache_headers(); | |
| 214 | 245 | header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s', $stat['mtime'] ) . ' GMT' ); |
| 215 | 246 | header( 'Content-Length: ' . ( strlen( $pre_output ) + strlen( $buf ) ) ); |
| 216 | 247 | header( 'Content-Type: ' . concat_get_mtype( $latest_file ) ); |
| 217 | 248 | |
| @@ -224,13 +255,15 @@ | ||
| 224 | 255 | |
| 225 | 256 | $fullpath = concat_get_path( $uri ); |
| 226 | 257 | |
| 227 | 258 | if ( ! file_exists( $fullpath ) ) { |
| 259 | + maybe_add_debug_log( sprintf( "File Optimizer 404 - Missing file: %s", $fullpath ) ); | |
| 228 | 260 | concat_http_status_exit( 404 ); |
| 229 | 261 | } |
| 230 | 262 | |
| 231 | 263 | $mime_type = concat_get_mtype( $fullpath ); |
| 232 | 264 | if ( ! in_array( $mime_type, $concat_types ) ) { |
| 265 | + maybe_add_debug_log( sprintf( "File Optimizer 400 - Unsupported mime type: %s", $mime_type ) ); | |
| 233 | 266 | concat_http_status_exit( 400 ); |
| 234 | 267 | } |
| 235 | 268 | |
| 236 | 269 | if ( $concat_unique ) { |
| @@ -238,8 +271,9 @@ | ||
| 238 | 271 | $last_mime_type = $mime_type; |
| 239 | 272 | } |
| 240 | 273 | |
| 241 | 274 | if ( $last_mime_type != $mime_type ) { |
| 275 | + maybe_add_debug_log( sprintf( "File Optimizer 400 - Different mime type: last mime %s vs current mime: %s", $last_mime_type, $mime_type ) ); | |
| 242 | 276 | concat_http_status_exit( 400 ); |
| 243 | 277 | } |
| 244 | 278 | } |
| 245 | 279 | |
| @@ -244,8 +278,9 @@ | ||
| 244 | 278 | } |
| 245 | 279 | |
| 246 | 280 | $stat = stat( $fullpath ); |
| 247 | 281 | if ( false === $stat ) { |
| 282 | + maybe_add_debug_log( sprintf( "File Optimizer 500 - false stat" ) ); | |
| 248 | 283 | concat_http_status_exit( 500 ); |
| 249 | 284 | } |
| 250 | 285 | |
| 251 | 286 | if ( $stat['mtime'] > $last_modified ) { |
| @@ -253,8 +288,9 @@ | ||
| 253 | 288 | } |
| 254 | 289 | |
| 255 | 290 | $buf = file_get_contents( $fullpath ); |
| 256 | 291 | if ( false === $buf ) { |
| 292 | + maybe_add_debug_log( sprintf( "File Optimizer 500 - false buffer" ) ); | |
| 257 | 293 | concat_http_status_exit( 500 ); |
| 258 | 294 | } |
| 259 | 295 | |
| 260 | 296 | if ( 'text/css' == $mime_type ) { |
| @@ -327,8 +363,9 @@ | ||
| 327 | 363 | $output = $css_minify->minify(); |
| 328 | 364 | } |
| 329 | 365 | } |
| 330 | 366 | |
| 367 | +set_cache_headers(); | |
| 331 | 368 | header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s', $last_modified ) . ' GMT' ); |
| 332 | 369 | header( 'Content-Length: ' . ( strlen( $pre_output ) + strlen( $output ) ) ); |
| 333 | 370 | header( "Content-Type: $mime_type" ); |
| 334 | 371 | |
| @@ -341,4 +378,68 @@ | ||
| 341 | 378 | $cache_file_name .= '.css'; |
| 342 | 379 | } |
| 343 | 380 | |
| 344 | 381 | file_put_contents( $cache_file_name, $pre_output . $output ); |
| 382 | + | |
| 383 | + | |
| 384 | +/** | |
| 385 | + * Normalize a filesystem path. | |
| 386 | + * | |
| 387 | + * On windows systems, replaces backslashes with forward slashes | |
| 388 | + * and forces upper-case drive letters. | |
| 389 | + * Allows for two leading slashes for Windows network shares, but | |
| 390 | + * ensures that all other duplicate slashes are reduced to a single. | |
| 391 | + * | |
| 392 | + * @param string $path Path to normalize. | |
| 393 | + * | |
| 394 | + * @return string Normalized path. | |
| 395 | + * @see wp_normalize_path | |
| 396 | + * | |
| 397 | + */ | |
| 398 | +function file_optimizer_normalize_path( $path ) { | |
| 399 | + $wrapper = ''; | |
| 400 | + | |
| 401 | + // Standardise all paths to use '/'. | |
| 402 | + $path = str_replace( '\\', '/', $path ); | |
| 403 | + | |
| 404 | + // Replace multiple slashes down to a singular, allowing for network shares having two slashes. | |
| 405 | + $path = preg_replace( '|(?<=.)/+|', '/', $path ); | |
| 406 | + | |
| 407 | + // Windows paths should uppercase the drive letter. | |
| 408 | + if ( ':' === substr( $path, 1, 1 ) ) { | |
| 409 | + $path = ucfirst( $path ); | |
| 410 | + } | |
| 411 | + | |
| 412 | + return $wrapper . $path; | |
| 413 | +} | |
| 414 | + | |
| 415 | +/** | |
| 416 | + * Maybe add debug message | |
| 417 | + * | |
| 418 | + * @param string $message Debug message | |
| 419 | + * | |
| 420 | + * @since 2.3 | |
| 421 | + */ | |
| 422 | +function maybe_add_debug_log( $message ) { | |
| 423 | + if ( defined( 'POWERED_CACHE_FO_DEBUG' ) && POWERED_CACHE_FO_DEBUG ) { | |
| 424 | + error_log( $message ); | |
| 425 | + } | |
| 426 | +} | |
| 427 | + | |
| 428 | + | |
| 429 | +/** | |
| 430 | + * Add cache headers | |
| 431 | + * | |
| 432 | + * @return void | |
| 433 | + * @since 2.5.3 | |
| 434 | + */ | |
| 435 | +function set_cache_headers() { | |
| 436 | + if ( defined( 'POWERED_CACHE_FO_DISABLE_CACHE_HEADERS' ) && POWERED_CACHE_FO_DISABLE_CACHE_HEADERS ) { | |
| 437 | + return; | |
| 438 | + } | |
| 439 | + | |
| 440 | + $ttl_in_seconds = 31536000; // 365 days | |
| 441 | + $ttl = gmdate( "D, d M Y H:i:s", time() + $ttl_in_seconds ) . " GMT"; | |
| 442 | + | |
| 443 | + header( "Expires: $ttl" ); | |
| 444 | + header( "Cache-Control: max-age=$ttl_in_seconds" ); | |
| 445 | +} | |