Code Duplication    Length = 313-313 lines in 2 locations

application/tests/_ci_phpunit_test/patcher/2.x/MonkeyPatchManager.php 1 location

@@ 18-330 (lines=313) @@
15
use PhpParser\ParserFactory;
16
use Kenjis\MonkeyPatch\Patcher\FunctionPatcher;
17
18
class MonkeyPatchManager
19
{
20
	public static $debug = false;
21
22
	private static $php_parser = ParserFactory::PREFER_PHP5;
23
24
	/**
25
	 * The path to the log file if `$debug` is true.
26
	 * Will be set in {@link MonkeyPatchManager::setDebug}.
27
	 * @var string|null */
28
	public static $log_file = null;
29
	private static $load_patchers = false;
30
	private static $exit_exception_classname =
31
		'Kenjis\MonkeyPatch\Exception\ExitException';
32
	/**
33
	 * @var array list of patcher classname
34
	 */
35
	private static $patcher_list = [
36
		'ExitPatcher',
37
		'FunctionPatcher',
38
		'MethodPatcher',
39
		'ConstantPatcher',
40
	];
41
42
	public static function log($message)
43
	{
44
		if (! self::$debug)
45
		{
46
			return;
47
		}
48
49
		$time = date('Y-m-d H:i:s');
50
		list($usec, $sec) = explode(' ', microtime());
51
		$usec = substr($usec, 1);
52
		$log = "[$time $usec] $message\n";
53
		file_put_contents(self::$log_file, $log, FILE_APPEND);
54
	}
55
56
	public static function setExitExceptionClassname($name)
57
	{
58
		self::$exit_exception_classname = $name;
59
	}
60
61
	public static function getExitExceptionClassname()
62
	{
63
		return self::$exit_exception_classname;
64
	}
65
66
	public static function getPhpParser()
67
	{
68
		return self::$php_parser;
69
	}
70
71
	protected static function setDebug(array $config)
72
	{
73
		if (isset($config['debug']))
74
		{
75
			self::$debug = $config['debug'];
76
		}
77
		if (isset($config['log_file']))
78
		{
79
			self::$debug = $config['log_file'];
80
		}
81
		if (is_null(self::$log_file))
82
		{
83
			self::$log_file = __DIR__ . '/debug.log';
84
		}
85
	}
86
87
	protected static function setDir(array $config)
88
	{
89
		if (isset($config['root_dir']))
90
		{
91
			Cache::setProjectRootDir($config['root_dir']);
92
		}
93
		else
94
		{
95
			// APPPATH is constant in CodeIgniter
96
			Cache::setProjectRootDir(APPPATH . '../');
97
		}
98
99
		if (! isset($config['cache_dir']))
100
		{
101
			throw new LogicException('You have to set "cache_dir"');
102
		}
103
		self::setCacheDir($config['cache_dir']);
104
	}
105
106
	protected static function setPaths(array $config)
107
	{
108
		if (! isset($config['include_paths']))
109
		{
110
			throw new LogicException('You have to set "include_paths"');
111
		}
112
		self::setIncludePaths($config['include_paths']);
113
114
		if (isset($config['exclude_paths']))
115
		{
116
			self::setExcludePaths($config['exclude_paths']);
117
		}
118
	}
119
120
	public static function init(array $config)
121
	{
122
		self::setDebug($config);
123
124
		if (isset($config['php_parser']))
125
		{
126
			self::$php_parser = constant('PhpParser\ParserFactory::'.$config['php_parser']);
127
		}
128
129
		self::setDir($config);
130
		self::setPaths($config);
131
132
		Cache::createTmpListDir();
133
134
		if (isset($config['patcher_list']))
135
		{
136
			self::setPatcherList($config['patcher_list']);
137
		}
138
		self::checkPatcherListUpdate();
139
		self::checkPathsUpdate();
140
141
		self::loadPatchers();
142
143
		self::addTmpFunctionBlacklist();
144
145
		if (isset($config['functions_to_patch']))
146
		{
147
			FunctionPatcher::addWhitelists($config['functions_to_patch']);
148
		}
149
		self::checkFunctionWhitelistUpdate();
150
		FunctionPatcher::lockFunctionList();
151
152
		if (isset($config['exit_exception_classname']))
153
		{
154
			self::setExitExceptionClassname($config['exit_exception_classname']);
155
		}
156
157
		// Register include stream wrapper for monkey patching
158
		self::wrap();
159
	}
160
161
	protected static function checkPathsUpdate()
162
	{
163
		$cached = Cache::getTmpIncludePaths();
164
		$current = PathChecker::getIncludePaths();
165
166
		// Updated?
167
		if ($cached !== $current)
168
		{
169
			MonkeyPatchManager::log('clear_src_cache: from ' . __METHOD__);
170
			Cache::clearSrcCache();
171
			Cache::writeTmpIncludePaths($current);
172
		}
173
174
		$cached = Cache::getTmpExcludePaths();
175
		$current = PathChecker::getExcludePaths();
176
177
		// Updated?
178
		if ($cached !== $current)
179
		{
180
			MonkeyPatchManager::log('clear_src_cache: from ' . __METHOD__);
181
			Cache::clearSrcCache();
182
			Cache::writeTmpExcludePaths($current);
183
		}
184
	}
185
186
	protected static function checkPatcherListUpdate()
187
	{
188
		$cached = Cache::getTmpPatcherList();
189
190
		// Updated?
191
		if ($cached !== self::$patcher_list)
192
		{
193
			MonkeyPatchManager::log('clear_src_cache: from ' . __METHOD__);
194
			Cache::clearSrcCache();
195
			Cache::writeTmpPatcherList(self::$patcher_list);
196
		}
197
	}
198
199
	protected static function checkFunctionWhitelistUpdate()
200
	{
201
		$cached = Cache::getTmpFunctionWhitelist();
202
		$current = FunctionPatcher::getFunctionWhitelist();
203
204
		// Updated?
205
		if ($cached !== $current)
206
		{
207
			MonkeyPatchManager::log('clear_src_cache: from ' . __METHOD__);
208
			Cache::clearSrcCache();
209
			Cache::writeTmpFunctionWhitelist($current);
210
		}
211
	}
212
213
	protected static function addTmpFunctionBlacklist()
214
	{
215
		$list = file(Cache::getTmpFunctionBlacklistFile());
216
		foreach ($list as $function)
217
		{
218
			FunctionPatcher::addBlacklist(trim($function));
219
		}
220
	}
221
222
	public static function isEnabled($patcher)
223
	{
224
		return in_array($patcher, self::$patcher_list);
225
	}
226
227
	public static function setPatcherList(array $list)
228
	{
229
		if (self::$load_patchers)
230
		{
231
			throw new LogicException("Can't change patcher list after initialisation");
232
		}
233
234
		self::$patcher_list = $list;
235
	}
236
237
	public static function setCacheDir($dir)
238
	{
239
		Cache::setCacheDir($dir);
240
	}
241
242
	public static function setIncludePaths(array $dir_list)
243
	{
244
		PathChecker::setIncludePaths($dir_list);
245
	}
246
247
	public static function setExcludePaths(array $dir_list)
248
	{
249
		PathChecker::setExcludePaths($dir_list);
250
	}
251
252
	public static function wrap()
253
	{
254
		IncludeStream::wrap();
255
	}
256
257
	public static function unwrap()
258
	{
259
		IncludeStream::unwrap();
260
	}
261
262
	/**
263
	 * @param string $path original source file path
264
	 * @return resource
265
	 * @throws LogicException
266
	 */
267
	public static function patch($path)
268
	{
269
		if (! is_readable($path))
270
		{
271
			throw new LogicException("Can't read '$path'");
272
		}
273
274
		// Check cache file
275
		if ($cache_file = Cache::getValidSrcCachePath($path))
276
		{
277
			self::log('cache_hit: ' . $path);
278
			return fopen($cache_file, 'r');
279
		}
280
281
		self::log('cache_miss: ' . $path);
282
		$source = file_get_contents($path);
283
284
		list($new_source, $patched) = self::execPatchers($source);
285
286
		// Write to cache file
287
		self::log('write_cache: ' . $path);
288
		Cache::writeSrcCacheFile($path, $new_source);
289
290
		$resource = fopen('php://memory', 'rb+');
291
		fwrite($resource, $new_source);
292
		rewind($resource);
293
		return $resource;
294
	}
295
296
	protected static function loadPatchers()
297
	{
298
		if (self::$load_patchers)
299
		{
300
			return;
301
		}
302
303
		require __DIR__ . '/Patcher/AbstractPatcher.php';
304
		require __DIR__ . '/Patcher/Backtrace.php';
305
306
		foreach (self::$patcher_list as $classname)
307
		{
308
			require __DIR__ . '/Patcher/' . $classname . '.php';
309
		}
310
311
		self::$load_patchers = true;
312
	}
313
314
	protected static function execPatchers($source)
315
	{
316
		$patched = false;
317
		foreach (self::$patcher_list as $classname)
318
		{
319
			$classname = 'Kenjis\MonkeyPatch\Patcher\\' . $classname;
320
			$patcher = new $classname;
321
			list($source, $patched_this) = $patcher->patch($source);
322
			$patched = $patched || $patched_this;
323
		}
324
325
		return [
326
			$source,
327
			$patched,
328
		];
329
	}
330
}
331

application/tests/_ci_phpunit_test/patcher/3.x/MonkeyPatchManager.php 1 location

@@ 18-330 (lines=313) @@
15
use PhpParser\ParserFactory;
16
use Kenjis\MonkeyPatch\Patcher\FunctionPatcher;
17
18
class MonkeyPatchManager
19
{
20
	public static $debug = false;
21
22
	private static $php_parser = ParserFactory::PREFER_PHP5;
23
24
	/**
25
	 * The path to the log file if `$debug` is true.
26
	 * Will be set in {@link MonkeyPatchManager::setDebug}.
27
	 * @var string|null */
28
	public static $log_file = null;
29
	private static $load_patchers = false;
30
	private static $exit_exception_classname =
31
		'Kenjis\MonkeyPatch\Exception\ExitException';
32
	/**
33
	 * @var array list of patcher classname
34
	 */
35
	private static $patcher_list = [
36
		'ExitPatcher',
37
		'FunctionPatcher',
38
		'MethodPatcher',
39
		'ConstantPatcher',
40
	];
41
42
	public static function log($message)
43
	{
44
		if (! self::$debug)
45
		{
46
			return;
47
		}
48
49
		$time = date('Y-m-d H:i:s');
50
		list($usec, $sec) = explode(' ', microtime());
51
		$usec = substr($usec, 1);
52
		$log = "[$time $usec] $message\n";
53
		file_put_contents(self::$log_file, $log, FILE_APPEND);
54
	}
55
56
	public static function setExitExceptionClassname($name)
57
	{
58
		self::$exit_exception_classname = $name;
59
	}
60
61
	public static function getExitExceptionClassname()
62
	{
63
		return self::$exit_exception_classname;
64
	}
65
66
	public static function getPhpParser()
67
	{
68
		return self::$php_parser;
69
	}
70
71
	protected static function setDebug(array $config)
72
	{
73
		if (isset($config['debug']))
74
		{
75
			self::$debug = $config['debug'];
76
		}
77
		if (isset($config['log_file']))
78
		{
79
			self::$debug = $config['log_file'];
80
		}
81
		if (self::$debug && is_null(self::$log_file))
82
		{
83
			self::$log_file = __DIR__ . '/debug.log';
84
		}
85
	}
86
87
	protected static function setDir(array $config)
88
	{
89
		if (isset($config['root_dir']))
90
		{
91
			Cache::setProjectRootDir($config['root_dir']);
92
		}
93
		else
94
		{
95
			// APPPATH is constant in CodeIgniter
96
			Cache::setProjectRootDir(APPPATH . '../');
97
		}
98
99
		if (! isset($config['cache_dir']))
100
		{
101
			throw new LogicException('You have to set "cache_dir"');
102
		}
103
		self::setCacheDir($config['cache_dir']);
104
	}
105
106
	protected static function setPaths(array $config)
107
	{
108
		if (! isset($config['include_paths']))
109
		{
110
			throw new LogicException('You have to set "include_paths"');
111
		}
112
		self::setIncludePaths($config['include_paths']);
113
114
		if (isset($config['exclude_paths']))
115
		{
116
			self::setExcludePaths($config['exclude_paths']);
117
		}
118
	}
119
120
	public static function init(array $config)
121
	{
122
		self::setDebug($config);
123
124
		if (isset($config['php_parser']))
125
		{
126
			self::$php_parser = constant('PhpParser\ParserFactory::'.$config['php_parser']);
127
		}
128
129
		self::setDir($config);
130
		self::setPaths($config);
131
132
		Cache::createTmpListDir();
133
134
		if (isset($config['patcher_list']))
135
		{
136
			self::setPatcherList($config['patcher_list']);
137
		}
138
		self::checkPatcherListUpdate();
139
		self::checkPathsUpdate();
140
141
		self::loadPatchers();
142
143
		self::addTmpFunctionBlacklist();
144
145
		if (isset($config['functions_to_patch']))
146
		{
147
			FunctionPatcher::addWhitelists($config['functions_to_patch']);
148
		}
149
		self::checkFunctionWhitelistUpdate();
150
		FunctionPatcher::lockFunctionList();
151
152
		if (isset($config['exit_exception_classname']))
153
		{
154
			self::setExitExceptionClassname($config['exit_exception_classname']);
155
		}
156
157
		// Register include stream wrapper for monkey patching
158
		self::wrap();
159
	}
160
161
	protected static function checkPathsUpdate()
162
	{
163
		$cached = Cache::getTmpIncludePaths();
164
		$current = PathChecker::getIncludePaths();
165
166
		// Updated?
167
		if ($cached !== $current)
168
		{
169
			MonkeyPatchManager::log('clear_src_cache: from ' . __METHOD__);
170
			Cache::clearSrcCache();
171
			Cache::writeTmpIncludePaths($current);
172
		}
173
174
		$cached = Cache::getTmpExcludePaths();
175
		$current = PathChecker::getExcludePaths();
176
177
		// Updated?
178
		if ($cached !== $current)
179
		{
180
			MonkeyPatchManager::log('clear_src_cache: from ' . __METHOD__);
181
			Cache::clearSrcCache();
182
			Cache::writeTmpExcludePaths($current);
183
		}
184
	}
185
186
	protected static function checkPatcherListUpdate()
187
	{
188
		$cached = Cache::getTmpPatcherList();
189
190
		// Updated?
191
		if ($cached !== self::$patcher_list)
192
		{
193
			MonkeyPatchManager::log('clear_src_cache: from ' . __METHOD__);
194
			Cache::clearSrcCache();
195
			Cache::writeTmpPatcherList(self::$patcher_list);
196
		}
197
	}
198
199
	protected static function checkFunctionWhitelistUpdate()
200
	{
201
		$cached = Cache::getTmpFunctionWhitelist();
202
		$current = FunctionPatcher::getFunctionWhitelist();
203
204
		// Updated?
205
		if ($cached !== $current)
206
		{
207
			MonkeyPatchManager::log('clear_src_cache: from ' . __METHOD__);
208
			Cache::clearSrcCache();
209
			Cache::writeTmpFunctionWhitelist($current);
210
		}
211
	}
212
213
	protected static function addTmpFunctionBlacklist()
214
	{
215
		$list = file(Cache::getTmpFunctionBlacklistFile());
216
		foreach ($list as $function)
217
		{
218
			FunctionPatcher::addBlacklist(trim($function));
219
		}
220
	}
221
222
	public static function isEnabled($patcher)
223
	{
224
		return in_array($patcher, self::$patcher_list);
225
	}
226
227
	public static function setPatcherList(array $list)
228
	{
229
		if (self::$load_patchers)
230
		{
231
			throw new LogicException("Can't change patcher list after initialisation");
232
		}
233
234
		self::$patcher_list = $list;
235
	}
236
237
	public static function setCacheDir($dir)
238
	{
239
		Cache::setCacheDir($dir);
240
	}
241
242
	public static function setIncludePaths(array $dir_list)
243
	{
244
		PathChecker::setIncludePaths($dir_list);
245
	}
246
247
	public static function setExcludePaths(array $dir_list)
248
	{
249
		PathChecker::setExcludePaths($dir_list);
250
	}
251
252
	public static function wrap()
253
	{
254
		IncludeStream::wrap();
255
	}
256
257
	public static function unwrap()
258
	{
259
		IncludeStream::unwrap();
260
	}
261
262
	/**
263
	 * @param string $path original source file path
264
	 * @return resource
265
	 * @throws LogicException
266
	 */
267
	public static function patch($path)
268
	{
269
		if (! is_readable($path))
270
		{
271
			throw new LogicException("Can't read '$path'");
272
		}
273
274
		// Check cache file
275
		if ($cache_file = Cache::getValidSrcCachePath($path))
276
		{
277
			self::log('cache_hit: ' . $path);
278
			return fopen($cache_file, 'r');
279
		}
280
281
		self::log('cache_miss: ' . $path);
282
		$source = file_get_contents($path);
283
284
		list($new_source, $patched) = self::execPatchers($source);
285
286
		// Write to cache file
287
		self::log('write_cache: ' . $path);
288
		Cache::writeSrcCacheFile($path, $new_source);
289
290
		$resource = fopen('php://memory', 'rb+');
291
		fwrite($resource, $new_source);
292
		rewind($resource);
293
		return $resource;
294
	}
295
296
	protected static function loadPatchers()
297
	{
298
		if (self::$load_patchers)
299
		{
300
			return;
301
		}
302
303
		require __DIR__ . '/Patcher/AbstractPatcher.php';
304
		require __DIR__ . '/Patcher/Backtrace.php';
305
306
		foreach (self::$patcher_list as $classname)
307
		{
308
			require __DIR__ . '/Patcher/' . $classname . '.php';
309
		}
310
311
		self::$load_patchers = true;
312
	}
313
314
	protected static function execPatchers($source)
315
	{
316
		$patched = false;
317
		foreach (self::$patcher_list as $classname)
318
		{
319
			$classname = 'Kenjis\MonkeyPatch\Patcher\\' . $classname;
320
			$patcher = new $classname;
321
			list($source, $patched_this) = $patcher->patch($source);
322
			$patched = $patched || $patched_this;
323
		}
324
325
		return [
326
			$source,
327
			$patched,
328
		];
329
	}
330
}
331