PluginProbe
Solid Performance – Your No-Code Caching, Performance, & Page Speed Solution / 2.0.0
Solid Performance – Your No-Code Caching, Performance, & Page Speed Solution v2.0.0
2.0.1 trunk 1.0.0 1.1.0 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.4.1 1.4.2 1.5.0 1.6.0 1.6.1 1.7.0 1.7.1 1.8.0 1.9.0 2.0.0
solid-performance / src / Performance / Page_Cache / Cache_Handler.php

Cache_Handler.php in Solid Performance – Your No-Code Caching, Performance, & Page Speed Solution 2.0.0, at src/Performance/Page_Cache/Cache_Handler.php

199 lines 5.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles managing cache files.
4 *
5 * @package SolidWP\Performance
6 */
7
8 declare( strict_types=1 );
9
10 namespace SolidWP\Performance\Page_Cache;
11
12 use InvalidArgumentException;
13 use RuntimeException;
14 use SolidWP\Performance\Http\Request;
15 use SolidWP\Performance\Page_Cache\Compression\Collection;
16 use SolidWP\Performance\Page_Cache\Compression\Contracts\Compressible;
17 use SolidWP\Performance\Page_Cache\Compression\Exceptions\CompressionFailedException;
18 use SolidWP\Performance\Page_Cache\Meta\Exceptions\MetadataNotWritableException;
19 use SolidWP\Performance\Page_Cache\Meta\Meta_Manager;
20 use SolidWP\Performance\Page_Cache\Request_Context\Device\Contracts\Device_Context;
21
22 /**
23 * Handles managing cache files.
24 *
25 * @package SolidWP\Performance
26 */
27 final class Cache_Handler {
28
29 /**
30 * @var Compressible
31 */
32 private Compressible $compressor;
33
34 /**
35 * @var Request
36 */
37 private Request $request;
38
39 /**
40 * @var Debug
41 */
42 private Debug $debug;
43
44 /**
45 * @var Expiration
46 */
47 private Expiration $expiration;
48
49 /**
50 * @var Cache_Path
51 */
52 private Cache_Path $cache_path;
53
54 /**
55 * @var Meta_Manager
56 */
57 private Meta_Manager $meta_manager;
58
59 /**
60 * @var Device_Context
61 */
62 private Device_Context $device_context;
63
64 /**
65 * @param Collection $compressors The collection of compression algorithms.
66 * @param Request $request The current request.
67 * @param Debug $debug The debugger.
68 * @param Expiration $expiration The expiration manager.
69 * @param Cache_Path $cache_path The server path to the cache directory.
70 * @param Meta_Manager $meta_manager The meta manager.
71 * @param Device_Context $device_context The device context.
72 */
73 public function __construct(
74 Collection $compressors,
75 Request $request,
76 Debug $debug,
77 Expiration $expiration,
78 Cache_Path $cache_path,
79 Meta_Manager $meta_manager,
80 Device_Context $device_context
81 ) {
82 $this->compressor = $compressors->get_by_header( (string) $request->header->get( 'accept-encoding' ) );
83 $this->request = $request;
84 $this->debug = $debug;
85 $this->expiration = $expiration;
86 $this->cache_path = $cache_path;
87 $this->meta_manager = $meta_manager;
88 $this->device_context = $device_context;
89 }
90
91 /**
92 * Save a file to the cache based on the type of compression the browser is asking for
93 * and what the server supports.
94 *
95 * @param string $output Output to save in the cached file.
96 *
97 * @throws RuntimeException If the cache directory or cache file can't be created.
98 * @throws InvalidArgumentException If the URL is empty.
99 * @throws MetadataNotWritableException If we can't write the metadata.
100 *
101 * @return void
102 */
103 public function save( string $output ): void {
104 $this->ensure_cache_dir_exists();
105
106 $file = $this->get_file_path();
107
108 // Append HTML debug comment, if enabled.
109 $output .= $this->debug->get_debug_comment( $this->request, $this->compressor );
110
111 // Append HTML generated by comment if debugging is DISABLED.
112 $output .= $this->debug->get_generated_by_comment();
113
114 // Don't save any fails that failed to compress their content.
115 try {
116 $compressed = $this->compressor->compress( $output );
117 } catch ( CompressionFailedException $e ) {
118 swpsp_log( sprintf( 'Failed to compress content using "%s" compression: %s', $this->compressor->encoding(), $e->getMessage() ) );
119
120 return;
121 }
122
123 $result = swpsp_direct_filesystem()->put_contents( $file, $compressed, swpsp_get_file_mode() );
124
125 if ( $result === false ) {
126 throw new RuntimeException( sprintf( 'File could not be saved to cache: %s', $file ) );
127 }
128
129 // Save the cache metadata.
130 $this->meta_manager->save( $this->request->uri );
131 }
132
133 /**
134 * Converts a URL into a directory structure, with dynamic mobile cache file support.
135 *
136 * All cached requests will be saved to a directory structure that matches
137 * the relative URL. This provides a way to consistently get the cached
138 * resource from the URL.
139 *
140 * @throws RuntimeException When URL does not have valid host.
141 *
142 * @return string
143 */
144 public function get_file_path(): string {
145 $path = $this->cache_path->get_path_from_url( $this->request->uri );
146 $device_suffix = $this->device_context->suffix();
147 $ext = $this->compressor->extension();
148
149 return "{$path}{$device_suffix}.{$ext}";
150 }
151
152 /**
153 * Whether the current cache file exists and is not expired.
154 *
155 * @return bool
156 */
157 public function is_valid(): bool {
158 return file_exists( $this->get_file_path() ) && ! $this->expiration->file_expired( $this->get_file_path() );
159 }
160
161 /**
162 * Get the current compression strategy.
163 *
164 * @return Compressible
165 */
166 public function compressor(): Compressible {
167 return $this->compressor;
168 }
169
170 /**
171 * Whether a mobile device is making this request.
172 *
173 * @return bool
174 */
175 public function is_mobile(): bool {
176 return (bool) $this->device_context->suffix();
177 }
178
179 /**
180 * Make sure the complete directory we'll be saving our file to, actually exists.
181 *
182 * @throws RuntimeException If the cache directory can't be created.
183 *
184 * @return void
185 */
186 private function ensure_cache_dir_exists(): void {
187 $dir = dirname( $this->get_file_path() );
188
189 // If the file's directory structure does not exist yet, create it.
190 if ( ! is_dir( $dir ) ) {
191 $result = wp_mkdir_p( $dir );
192
193 if ( ! $result ) {
194 throw new RuntimeException( 'Unable to make directory: ' . $dir );
195 }
196 }
197 }
198 }
199