1 | <?php |
||
17 | class Staticify extends \FMUP\Dispatcher\Plugin |
||
18 | { |
||
19 | const PROTOCOL = '://'; |
||
20 | |||
21 | protected $name = 'Staticify'; |
||
22 | /** |
||
23 | * Number of static instances |
||
24 | * @var int |
||
25 | */ |
||
26 | protected $staticNumber = 3; |
||
27 | |||
28 | /** |
||
29 | * Prefix of static instances |
||
30 | * @var string |
||
31 | */ |
||
32 | protected $staticPrefix = 'static'; |
||
33 | |||
34 | /** |
||
35 | * Suffix of static instances |
||
36 | * @var string |
||
37 | */ |
||
38 | protected $staticSuffix = ''; |
||
39 | /** |
||
40 | * SubDomain to replace |
||
41 | * @var string |
||
42 | */ |
||
43 | protected $subDomain = 'www'; |
||
44 | /** |
||
45 | * Domain to replace |
||
46 | * @var string |
||
47 | */ |
||
48 | protected $domain = null; |
||
49 | |||
50 | /** |
||
51 | * Current asset |
||
52 | * @var int |
||
53 | */ |
||
54 | private $currentAsset = 1; |
||
55 | |||
56 | /** |
||
57 | * Path between domain and requested asset for relative urls |
||
58 | * @var string |
||
59 | */ |
||
60 | private $trailingPath; |
||
61 | |||
62 | /** |
||
63 | * Will catch all resources URL |
||
64 | * |
||
65 | * @see self::computeAsset |
||
66 | */ |
||
67 | 2 | public function handle() |
|
68 | { |
||
69 | 2 | $response = $this->getResponse()->getBody(); |
|
70 | 2 | $newResponse = $response; |
|
71 | 2 | $isJson = $this->isRequestJson(); |
|
72 | 2 | if ($isJson) { |
|
73 | 1 | $response = stripslashes($response); |
|
74 | } |
||
75 | $regexps = array( |
||
76 | 2 | '~<[^>]+\ssrc=["\']([^"\']+)["\']~', |
|
77 | '~<link\s[^>]*href=["\']([^"\']+)["\']~', |
||
78 | ); |
||
79 | 2 | $values = array(); |
|
80 | 2 | foreach ($regexps as $exp) { |
|
81 | 2 | preg_match_all($exp, $response, $glob); |
|
82 | 2 | foreach ($glob[1] as $string) { |
|
83 | 2 | $crc = crc32($string); |
|
84 | 2 | if (!isset($values[$crc])) { |
|
85 | 2 | $newResponse = str_replace( |
|
86 | 2 | $this->jsonTransform($string, $isJson), |
|
87 | 2 | $this->computeAsset($string, $isJson), |
|
88 | 2 | $newResponse |
|
89 | ); |
||
90 | 2 | $values[$crc] = 1; |
|
91 | } |
||
92 | } |
||
93 | } |
||
94 | 2 | $this->getResponse()->setBody($newResponse); |
|
95 | 2 | } |
|
96 | |||
97 | /** |
||
98 | * Check whether response is json or not |
||
99 | * @return bool |
||
100 | * @throws \FMUP\Exception |
||
101 | */ |
||
102 | 2 | private function isRequestJson() |
|
103 | { |
||
104 | 2 | $isJson = false; |
|
105 | 2 | foreach ($this->getResponse()->getHeaders() as $type => $items) { |
|
106 | 1 | if ($type == \FMUP\Response\Header\ContentType::TYPE) { |
|
107 | 1 | foreach ($items as $item) { |
|
108 | 1 | if ($item instanceof \FMUP\Response\Header\ContentType && |
|
109 | 1 | $item->getMime() == \FMUP\Response\Header\ContentType::MIME_APPLICATION_JSON |
|
110 | ) { |
||
111 | 1 | $isJson = true; |
|
112 | 1 | break; |
|
113 | } |
||
114 | } |
||
115 | } |
||
116 | } |
||
117 | 2 | return $isJson; |
|
118 | } |
||
119 | |||
120 | /** |
||
121 | * add slashes to / character in json mode |
||
122 | * @param string $string |
||
123 | * @param bool $isJson |
||
124 | * @return mixed |
||
125 | */ |
||
126 | 2 | private function jsonTransform($string, $isJson) |
|
130 | |||
131 | /** |
||
132 | * Compute which asset for a path and return the full path |
||
133 | * |
||
134 | * @param string $path |
||
135 | * @param bool $isJson Check if url should be encoded |
||
136 | * |
||
137 | * @return string |
||
138 | */ |
||
139 | 2 | protected function computeAsset($path, $isJson = false) |
|
140 | { |
||
141 | 2 | if (strpos($path, self::PROTOCOL) !== false) { |
|
142 | 2 | return $this->jsonTransform($path, $isJson); |
|
143 | } |
||
144 | 2 | $trailingPath = ($path{0} !== '/') ? $this->getAssetPath() : ''; |
|
145 | 2 | $path = $this->getDomain() . $trailingPath . $path; |
|
146 | 2 | $path = str_replace( |
|
147 | 2 | self::PROTOCOL . $this->getSubDomain(), |
|
148 | 2 | self::PROTOCOL . $this->getStaticPrefix() . $this->currentAsset++ . $this->getStaticSuffix(), |
|
149 | 2 | $path |
|
150 | ); |
||
151 | 2 | if ($this->currentAsset > $this->getStaticNumber()) { |
|
152 | 2 | $this->currentAsset = 1; |
|
153 | } |
||
154 | 2 | return $this->jsonTransform($path, $isJson); |
|
155 | } |
||
156 | |||
157 | /** |
||
158 | * Compute relative path between requested asset and current path on request URI |
||
159 | * @return string |
||
160 | * @throws \FMUP\Exception |
||
161 | */ |
||
162 | 2 | private function getAssetPath() |
|
163 | { |
||
164 | 2 | if (!$this->trailingPath) { |
|
165 | 2 | $request = $this->getRequest(); |
|
166 | /** @var $request \FMUP\Request\Http */ |
||
167 | 2 | $uri = $request->getServer(\FMUP\Request\Http::REQUEST_URI); |
|
168 | 2 | $this->trailingPath = ($uri{strlen($uri) - 1} == '/' ? dirname($uri . 'random') : dirname($uri)) . '/'; |
|
169 | } |
||
170 | 2 | return $this->trailingPath; |
|
171 | } |
||
172 | |||
173 | /** |
||
174 | * @param int $number |
||
175 | * @return $this |
||
176 | */ |
||
177 | 1 | public function setStaticNumber($number = 3) |
|
182 | |||
183 | /** |
||
184 | * @return int |
||
185 | */ |
||
186 | 3 | public function getStaticNumber() |
|
190 | |||
191 | /** |
||
192 | * @param string $prefix |
||
193 | * @return $this |
||
194 | */ |
||
195 | 1 | public function setStaticPrefix($prefix = 'static') |
|
200 | |||
201 | /** |
||
202 | * @return string |
||
203 | */ |
||
204 | 2 | public function getStaticPrefix() |
|
208 | |||
209 | /** |
||
210 | * @param string $suffix |
||
211 | * @return $this |
||
212 | */ |
||
213 | 1 | public function setStaticSuffix($suffix = '') |
|
218 | |||
219 | /** |
||
220 | * @return string |
||
221 | */ |
||
222 | 2 | public function getStaticSuffix() |
|
226 | |||
227 | /** |
||
228 | * @param string $subDomain |
||
229 | * @return $this |
||
230 | */ |
||
231 | 1 | public function setSubDomain($subDomain = 'www') |
|
236 | |||
237 | /** |
||
238 | * @return string |
||
239 | */ |
||
240 | 2 | public function getSubDomain() |
|
244 | |||
245 | /** |
||
246 | * @return string |
||
247 | * @throws \FMUP\Exception |
||
248 | */ |
||
249 | 1 | public function getDomain() |
|
250 | { |
||
251 | 1 | if ($this->domain === null) { |
|
252 | /** @var \FMUP\Request\Http $request */ |
||
253 | 1 | $request = $this->getRequest(); |
|
254 | 1 | $this->domain = $request->getServer(\FMUP\Request\Http::REQUEST_SCHEME) |
|
255 | 1 | . self::PROTOCOL . $request->getServer(\FMUP\Request\Http::HTTP_HOST); |
|
256 | } |
||
257 | 1 | return $this->domain; |
|
258 | } |
||
259 | |||
260 | /** |
||
261 | * Define domain to use for static assets |
||
262 | * @param string|null $domain |
||
263 | * @return $this |
||
264 | */ |
||
265 | 1 | public function setDomain($domain = null) |
|
270 | } |
||
271 |