1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
19:
20: App::uses('AppHelper', 'View/Helper');
21:
22: 23: 24: 25: 26: 27: 28: 29: 30:
31: class CacheHelper extends AppHelper {
32:
33: 34: 35: 36: 37: 38:
39: protected $_replace = array();
40:
41: 42: 43: 44: 45: 46:
47: protected $_match = array();
48:
49: 50: 51: 52: 53:
54: protected $_counter = 0;
55:
56: 57: 58: 59: 60: 61:
62: public function afterRender($viewFile) {
63: $caching = (($this->_View->cacheAction != false)) && (Configure::read('Cache.check') === true);
64: if ($caching) {
65: $this->_View->output = $this->cache($viewFile, $this->_View->output, false);
66: }
67: }
68:
69: 70: 71: 72: 73: 74:
75: public function afterLayout($layoutFile) {
76: $caching = (($this->_View->cacheAction != false)) && (Configure::read('Cache.check') === true);
77: if ($caching) {
78: $this->_View->output = $this->cache($layoutFile, $this->_View->output, true);
79: }
80: $this->_View->output = preg_replace('/<!--\/?nocache-->/', '', $this->_View->output);
81: }
82:
83: 84: 85: 86: 87: 88: 89: 90: 91:
92: public function cache($file, $out, $cache = false) {
93: $cacheTime = 0;
94: $useCallbacks = false;
95: $cacheAction = $this->_View->cacheAction;
96:
97: if (is_array($cacheAction)) {
98: $keys = array_keys($cacheAction);
99: $index = null;
100:
101: foreach ($keys as $action) {
102: if ($action == $this->request->params['action']) {
103: $index = $action;
104: break;
105: }
106: }
107:
108: if (!isset($index) && $this->request->params['action'] == 'index') {
109: $index = 'index';
110: }
111:
112: $options = $cacheAction;
113: if (isset($cacheAction[$index])) {
114: if (is_array($cacheAction[$index])) {
115: $options = array_merge(array('duration' => 0, 'callbacks' => false), $cacheAction[$index]);
116: } else {
117: $cacheTime = $cacheAction[$index];
118: }
119: }
120: if (isset($options['duration'])) {
121: $cacheTime = $options['duration'];
122: }
123: if (isset($options['callbacks'])) {
124: $useCallbacks = $options['callbacks'];
125: }
126: } else {
127: $cacheTime = $cacheAction;
128: }
129:
130: if ($cacheTime != '' && $cacheTime > 0) {
131: $out = preg_replace_callback('/<!--nocache-->/', array($this, '_replaceSection'), $out);
132:
133: $this->_parseFile($file, $out);
134: if ($cache === true) {
135: $cached = $this->_parseOutput($out);
136: $this->_writeFile($cached, $cacheTime, $useCallbacks);
137: $out = $this->_stripTags($out);
138: }
139: return $out;
140: } else {
141: return $out;
142: }
143: }
144:
145: 146: 147: 148: 149: 150: 151:
152: protected function _parseFile($file, $cache) {
153: if (is_file($file)) {
154: $file = file_get_contents($file);
155: } elseif ($file = fileExistsInPath($file)) {
156: $file = file_get_contents($file);
157: }
158: preg_match_all('/(<!--nocache:\d{3}-->(?<=<!--nocache:\d{3}-->)[\\s\\S]*?(?=<!--\/nocache-->)<!--\/nocache-->)/i', $cache, $outputResult, PREG_PATTERN_ORDER);
159: preg_match_all('/(?<=<!--nocache-->)([\\s\\S]*?)(?=<!--\/nocache-->)/i', $file, $fileResult, PREG_PATTERN_ORDER);
160: $fileResult = $fileResult[0];
161: $outputResult = $outputResult[0];
162:
163: if (!empty($this->_replace)) {
164: foreach ($outputResult as $i => $element) {
165: $index = array_search($element, $this->_match);
166: if ($index !== false) {
167: unset($outputResult[$i]);
168: }
169: }
170: $outputResult = array_values($outputResult);
171: }
172:
173: if (!empty($fileResult)) {
174: $i = 0;
175: foreach ($fileResult as $cacheBlock) {
176: if (isset($outputResult[$i])) {
177: $this->_replace[] = $cacheBlock;
178: $this->_match[] = $outputResult[$i];
179: }
180: $i++;
181: }
182: }
183: }
184:
185: 186: 187: 188: 189: 190:
191: protected function _replaceSection() {
192: $this->_counter += 1;
193: return sprintf('<!--nocache:%03d-->', $this->_counter);
194: }
195:
196: 197: 198: 199: 200: 201: 202: 203:
204: protected function _stripTags($content) {
205: return preg_replace('#<!--/?nocache(\:\d{3})?-->#', '', $content);
206: }
207:
208: 209: 210: 211: 212: 213:
214: protected function _parseOutput($cache) {
215: $count = 0;
216: if (!empty($this->_match)) {
217: foreach ($this->_match as $found) {
218: $original = $cache;
219: $length = strlen($found);
220: $position = 0;
221:
222: for ($i = 1; $i <= 1; $i++) {
223: $position = strpos($cache, $found, $position);
224:
225: if ($position !== false) {
226: $cache = substr($original, 0, $position);
227: $cache .= $this->_replace[$count];
228: $cache .= substr($original, $position + $length);
229: } else {
230: break;
231: }
232: }
233: $count++;
234: }
235: return $cache;
236: }
237: return $cache;
238: }
239:
240: 241: 242: 243: 244: 245: 246: 247:
248: protected function _writeFile($content, $timestamp, $useCallbacks = false) {
249: $now = time();
250:
251: if (is_numeric($timestamp)) {
252: $cacheTime = $now + $timestamp;
253: } else {
254: $cacheTime = strtotime($timestamp, $now);
255: }
256: $path = $this->request->here();
257: if ($path == '/') {
258: $path = 'home';
259: }
260: $cache = strtolower(Inflector::slug($path));
261:
262: if (empty($cache)) {
263: return;
264: }
265: $cache = $cache . '.php';
266: $file = '<!--cachetime:' . $cacheTime . '--><?php';
267:
268: if (empty($this->_View->plugin)) {
269: $file .= "
270: App::uses('{$this->_View->name}Controller', 'Controller');
271: ";
272: } else {
273: $file .= "
274: App::uses('{$this->_View->plugin}AppController', '{$this->_View->plugin}.Controller');
275: App::uses('{$this->_View->name}Controller', '{$this->_View->plugin}.Controller');
276: ";
277: }
278:
279: $file .= '
280: $request = unserialize(\'' . str_replace("'", "\\'", serialize($this->request)) . '\');
281: $response = new CakeResponse(array("charset" => Configure::read("App.encoding")));
282: $controller = new ' . $this->_View->name . 'Controller($request, $response);
283: $controller->plugin = $this->plugin = \'' . $this->_View->plugin . '\';
284: $controller->helpers = $this->helpers = unserialize(base64_decode(\'' . base64_encode(serialize($this->_View->helpers)) . '\'));
285: $controller->layout = $this->layout = \'' . $this->_View->layout . '\';
286: $controller->theme = $this->theme = \'' . $this->_View->theme . '\';
287: $controller->viewVars = unserialize(base64_decode(\'' . base64_encode(serialize($this->_View->viewVars)) . '\'));
288: Router::setRequestInfo($controller->request);
289: $this->request = $request;';
290:
291: if ($useCallbacks == true) {
292: $file .= '
293: $controller->constructClasses();
294: $controller->startupProcess();';
295: }
296:
297: $file .= '
298: $this->viewVars = $controller->viewVars;
299: $this->loadHelpers();
300: extract($this->viewVars, EXTR_SKIP);
301: ?>';
302: $content = preg_replace("/(<\\?xml)/", "<?php echo '$1';?>", $content);
303: $file .= $content;
304: return cache('views' . DS . $cache, $file, $timestamp);
305: }
306: }
307: