Passed
Push — 1.0.0-dev ( 93958a...e1c8ef )
by nguereza
02:26
created

FileCache::setLogger()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 1
eloc 2
c 1
b 1
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
	defined('ROOT_PATH') or exit('Access denied');
3
	/**
4
	 * TNH Framework
5
	 *
6
	 * A simple PHP framework using HMVC architecture
7
	 *
8
	 * This content is released under the GNU GPL License (GPL)
9
	 *
10
	 * Copyright (C) 2017 Tony NGUEREZA
11
	 *
12
	 * This program is free software; you can redistribute it and/or
13
	 * modify it under the terms of the GNU General Public License
14
	 * as published by the Free Software Foundation; either version 3
15
	 * of the License, or (at your option) any later version.
16
	 *
17
	 * This program is distributed in the hope that it will be useful,
18
	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
	 * GNU General Public License for more details.
21
	 *
22
	 * You should have received a copy of the GNU General Public License
23
	 * along with this program; if not, write to the Free Software
24
	 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25
	*/
26
27
	class FileCache extends BaseClass implements CacheInterface{
28
		
29
		/**
30
		 * Whether to enable compression of the cache data file.
31
		 * @var boolean
32
		 */
33
		private $compressCacheData = true;
34
35
		/**
36
		 * Class constructor
37
		 */
38
		public function __construct(){
39
			parent::__construct();
40
			if(! $this->isSupported()){
41
				show_error('The cache for file system is not available. Check the cache directory if is exists or is writable.');
42
			}
43
			
44
			//if Zlib extension is not loaded set compressCacheData to false
45
			if(! extension_loaded('zlib')){
46
				$this->logger->warning('The zlib extension is not loaded set cache compress data to FALSE');
47
				$this->compressCacheData = false;
48
			}
49
		}
50
51
		/**
52
		 * This is used to get the cache data using the key
53
		 * @param  string $key the key to identify the cache data
54
		 * @return mixed      the cache data if exists else return false
55
		 */
56
		public function get($key){
57
			$this->logger->debug('Getting cache data for key ['. $key .']');
58
			$filePath = $this->getFilePath($key);
59
			if(! file_exists($filePath)){
60
				$this->logger->info('No cache file found for the key ['. $key .'], return false');
61
				return false;
62
			}
63
			$this->logger->info('The cache file [' .$filePath. '] for the key ['. $key .'] exists, check if the cache data is valid');
64
			$handle = fopen($filePath,'r');
65
			if(! is_resource($handle)){
66
				$this->logger->error('Can not open the file cache [' .$filePath. '] for the key ['. $key .'], return false');
67
				return false;
68
			}
69
			// Getting a shared lock 
70
		    flock($handle, LOCK_SH);
71
		    $data = file_get_contents($filePath);
72
      		fclose($handle);
73
      		$data = @unserialize($this->compressCacheData ? gzinflate($data) : $data);
74
      		if (! $data) {
75
      			$this->logger->error('Can not unserialize the cache data for the key ['. $key .'], return false');
76
		         // If unserializing somehow didn't work out, we'll delete the file
77
		         unlink($filePath);
78
		         return false;
79
	      	}
80
	      	if (time() > $data['expire']) {
81
	      		$this->logger->info('The cache data for the key ['. $key .'] already expired delete the cache file [' .$filePath. ']');
82
		        // Unlinking when the file was expired
83
		        unlink($filePath);
84
		        return false;
85
		     }
86
		     else{
87
		     	$this->logger->info('The cache not yet expire, now return the cache data for key ['. $key .'], the cache will expire at [' . date('Y-m-d H:i:s', $data['expire']) . ']');
88
		     	return $data['data'];
89
		     }
90
		}
91
92
93
		/**
94
		 * Save data to the cache
95
		 * @param string  $key  the key to identify this cache data
96
		 * @param mixed  $data the cache data
97
		 * @param integer $ttl  the cache life time
98
		 * @return boolean true if success otherwise will return false
99
		 */
100
		public function set($key, $data, $ttl = 0){
101
			$expire = time() + $ttl;
102
			$this->logger->debug('Setting cache data for key ['. $key .'], time to live [' .$ttl. '], expire at [' . date('Y-m-d H:i:s', $expire) . ']');
103
			$filePath = $this->getFilePath($key);
104
			$handle = fopen($filePath,'w');
105
			if(! is_resource($handle)){
106
				$this->logger->error('Can not open the file cache [' .$filePath. '] for the key ['. $key .'], return false');
107
				return false;
108
			}
109
			flock($handle, LOCK_EX); // exclusive lock, will get released when the file is closed
110
			//Serializing along with the TTL
111
		    $cacheData = serialize(array(
112
									'mtime' => time(),
113
									'expire' => $expire,
114
									'data' => $data,
115
									'ttl' => $ttl
116
									)
117
								);		   
118
		    $result = fwrite($handle, $this->compressCacheData ? gzdeflate($cacheData, 9) : $cacheData);
119
		    if(! $result){
120
		    	$this->logger->error('Can not write cache data into file [' .$filePath. '] for the key ['. $key .'], return false');
121
		    	fclose($handle);
122
		    	return false;
123
		    }
124
		    else{
125
		    	$this->logger->info('Cache data saved into file [' .$filePath. '] for the key ['. $key .']');
126
		    	fclose($handle);
127
				chmod($filePath, 0640);
128
				return true;
129
		    }
130
		}	
131
132
133
		/**
134
		 * Delete the cache data for given key
135
		 * @param  string $key the key for cache to be deleted
136
		 * @return boolean      true if the cache is delete, false if can't delete 
137
		 * the cache or the cache with the given key not exist
138
		 */
139
		public function delete($key){
140
			$this->logger->debug('Deleting of cache data for key [' .$key. ']');
141
			$filePath = $this->getFilePath($key);
142
			$this->logger->info('The file path for the key [' .$key. '] is [' .$filePath. ']');
143
			if(! file_exists($filePath)){
144
				$this->logger->info('This cache file does not exists skipping');
145
				return false;
146
			}
147
			else{
148
				$this->logger->info('Found cache file [' .$filePath. '] remove it');
149
	      		unlink($filePath);
150
				return true;
151
			}
152
		}
153
		
154
		/**
155
		 * Get the cache information for given key
156
		 * @param  string $key the key for cache to get the information for
157
		 * @return boolean|array    the cache information. The associative array and must contains the following information:
158
		 * 'mtime' => creation time of the cache (Unix timestamp),
159
		 * 'expire' => expiration time of the cache (Unix timestamp),
160
		 * 'ttl' => the time to live of the cache in second
161
		 */
162
		public function getInfo($key){
163
			$this->logger->debug('Getting of cache info for key [' .$key. ']');
164
			$filePath = $this->getFilePath($key);
165
			$this->logger->info('The file path for the key [' .$key. '] is [' .$filePath. ']');
166
			if(! file_exists($filePath)){
167
				$this->logger->info('This cache file does not exists skipping');
168
				return false;
169
			}
170
			$this->logger->info('Found cache file [' .$filePath. '] check the validity');
171
      		$data = file_get_contents($filePath);
172
			$data = @unserialize($this->compressCacheData ? gzinflate($data) : $data);
173
			if(! $data){
174
				$this->logger->warning('Can not unserialize the cache data for file [' . $filePath . ']');
175
				return false;
176
			}
177
			$this->logger->info('This cache data is OK check for expire');
178
			if(isset($data['expire']) && $data['expire'] > time()){
179
				$this->logger->info('This cache not yet expired return cache informations');
180
				$info = array(
181
					'mtime' => $data['mtime'],
182
					'expire' => $data['expire'],
183
					'ttl' => $data['ttl']
184
					);
185
				return $info;
186
			}
187
			$this->logger->info('This cache already expired return false');
188
			return false;
189
		}
190
191
192
		/**
193
		 * Used to delete expired cache data
194
		 */
195
		public function deleteExpiredCache(){
196
			$this->logger->debug('Deleting of expired cache files');
197
			$list = glob(CACHE_PATH . '*.cache');
198
			if(! $list){
199
				$this->logger->info('No cache files were found skipping');
200
			}
201
			else{
202
				$this->logger->info('Found [' . count($list) . '] cache files to remove if expired');
203
				foreach ($list as $file) {
204
					$this->logger->debug('Processing the cache file [' . $file . ']');
205
					$data = file_get_contents($file);
206
		      		$data = @unserialize($this->compressCacheData ? gzinflate($data) : $data);
207
		      		if(! $data){
208
		      			$this->logger->warning('Can not unserialize the cache data for file [' . $file . ']');
209
		      		}
210
		      		else if(time() > $data['expire']){
211
		      			$this->logger->info('The cache data for file [' . $file . '] already expired remove it');
212
		      			unlink($file);
213
		      		}
214
		      		else{
215
		      			$this->logger->info('The cache data for file [' . $file . '] not yet expired skip it');
216
		      		}
217
				}
218
			}
219
		}	
220
221
		/**
222
		 * Remove all file from cache folder
223
		 */
224
		public function clean(){
225
			$this->logger->debug('Deleting of all cache files');
226
			$list = glob(CACHE_PATH . '*.cache');
227
			if(! $list){
228
				$this->logger->info('No cache files were found skipping');
229
			}
230
			else{
231
				$this->logger->info('Found [' . count($list) . '] cache files to remove');
232
				foreach ($list as $file) {
233
					$this->logger->debug('Processing the cache file [' . $file . ']');
234
					unlink($file);
235
				}
236
			}
237
		}
238
	
239
	    /**
240
	     * @return boolean
241
	     */
242
	    public function isCompressCacheData(){
243
	        return $this->compressCacheData;
244
	    }
245
246
	    /**
247
	     * @param boolean $compressCacheData
248
	     *
249
	     * @return object
250
	     */
251
	    public function setCompressCacheData($status = true){
252
			//if Zlib extension is not loaded set compressCacheData to false
253
			if($status === true && ! extension_loaded('zlib')){
254
				
255
				$this->logger->warning('The zlib extension is not loaded set cache compress data to FALSE');
256
				$this->compressCacheData = false;
257
			}
258
			else{
259
				$this->compressCacheData = $status;
260
			}
261
			return $this;
262
	    }
263
		
264
		/**
265
		 * Check whether the cache feature for the handle is supported
266
		 *
267
		 * @return bool
268
		 */
269
		public function isSupported(){
270
			return CACHE_PATH && is_dir(CACHE_PATH) && is_writable(CACHE_PATH);
271
		}
272
273
	
274
		/**
275
		* Get the cache file full path for the given key
276
		*
277
		* @param string $key the cache item key
278
		* @return string the full cache file path for this key
279
		*/
280
		private function getFilePath($key){
281
			return CACHE_PATH . md5($key) . '.cache';
282
		}
283
	}
284