PageRenderTime 49ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/administrator/components/com_akeeba/akeeba/abstract/filter.php

https://gitlab.com/endomorphosis/OLAAaction
PHP | 547 lines | 346 code | 55 blank | 146 comment | 44 complexity | d0d236d92ad29d24b4ffeb203c10f03d MD5 | raw file
  1. <?php
  2. /**
  3. * Akeeba Engine
  4. * The modular PHP5 site backup engine
  5. * @copyright Copyright (c)2009-2011 Nicholas K. Dionysopoulos
  6. * @license GNU GPL version 3 or, at your option, any later version
  7. * @package akeebaengine
  8. * @version $Id: filter.php 409 2011-01-24 09:30:22Z nikosdion $
  9. */
  10. // Protection against direct access
  11. defined('AKEEBAENGINE') or die('Restricted access');
  12. abstract class AEAbstractFilter extends AEAbstractObject
  13. {
  14. /** @var string Filter's internal name; defaults to filename without .php extension */
  15. public $filter_name = '';
  16. /** @var string The filtering object: dir|file|dbobject|db */
  17. public $object = 'dir';
  18. /** @var string The filtering subtype (all|content|children|inclusion) */
  19. public $subtype = null;
  20. /** @var string The filtering method (direct|regex|api) */
  21. public $method = 'direct';
  22. /** @var array An array holding filter or regex strings per root, i.e. $filter_data[$root] = array() */
  23. protected $filter_data = null;
  24. /**
  25. * Public constructor
  26. */
  27. public function __construct()
  28. {
  29. // Call AEAbstractObject's contructor
  30. parent::__construct();
  31. // Set the filter name if it's missing (filename in lowercase, minus the .php extension)
  32. if(empty($this->filter_name)) $this->filter_name = strtolower(basename(__FILE__,'.php'));
  33. }
  34. /**
  35. * This method must be overriden by API-type exclusion filters.
  36. * @param string $test The object to test for exclusion
  37. * @param string $root The object's root
  38. * @return bool Return true if it matches your filters
  39. */
  40. protected function is_excluded_by_api($test, $root)
  41. {
  42. return false;
  43. }
  44. /**
  45. * This method must be overriden by API-type inclusion filters.
  46. * @return array The inclusion filters
  47. */
  48. protected function &get_inclusions_by_api()
  49. {
  50. $dummy = array();
  51. return $dummy;
  52. }
  53. /**
  54. * Extra SQL statements to append to the SQL dump file. Useful for extension
  55. * filters which have to filter out specific database records. This method
  56. * must be overriden in children classes.
  57. * @param string $root The database for which to get the extra SQL statements
  58. * @return string Extra SQL statements
  59. */
  60. public function &getExtraSQL($root)
  61. {
  62. $dummy = "";
  63. return $dummy;
  64. }
  65. /**
  66. * Returns filtering (exclusion) status of the $test object
  67. * @param string $test The string to check for filter status (e.g. filename, dir name, table name, etc)
  68. * @param string $root The exclusion root test belongs to
  69. * @param string $object What type of object is it? dir|file|dbobject
  70. * @param string $subtype Filter subtype (all|content|children)
  71. * @return bool True if it excluded, false otherwise
  72. */
  73. public final function isFiltered($test, $root, $object, $subtype)
  74. {
  75. //AEUtilLogger::WriteLog(_AE_LOG_DEBUG,"Filtering [$object:$subtype] $root // $test");
  76. // Inclusion filters do not qualify for exclusion
  77. if( $this->subtype == 'inclusion' ) return false;
  78. // The object and subtype must match
  79. if( ($this->object != $object) || ($this->subtype != $subtype) ) return false;
  80. if( in_array($this->method, array('direct','regex')) )
  81. {
  82. // -- Direct or regex based filters --
  83. // Get a local reference of the filter data, if necessary
  84. if(is_null($this->filter_data))
  85. {
  86. $filters =& AEFactory::getFilters();
  87. $this->filter_data =& $filters->getFilterData($this->filter_name);
  88. }
  89. // Check if the root exists and if there's a filter for the $test
  90. if( !array_key_exists($root,$this->filter_data) )
  91. {
  92. // Root not found
  93. return false;
  94. }
  95. else
  96. {
  97. // Root found, search in the array
  98. if($this->method == 'direct')
  99. {
  100. // Direct filtering
  101. return in_array($test, $this->filter_data[$root]);
  102. }
  103. else
  104. {
  105. // Regex matching
  106. foreach($this->filter_data[$root] as $regex)
  107. {
  108. if(substr($regex,0,1) == '!')
  109. {
  110. // Custom Akeeba Backup extension to PCRE notation. If you put a ! before the PCRE, it negates the result of the PCRE.
  111. if( !preg_match( substr($regex,1), $test) ) return true;
  112. }
  113. else
  114. {
  115. // Normal PCRE
  116. if( preg_match($regex, $test) ) return true;
  117. }
  118. }
  119. // if we're here, no match exists
  120. return false;
  121. }
  122. }
  123. }
  124. else
  125. {
  126. // -- API-based filters --
  127. return $this->is_excluded_by_api($test, $root);
  128. }
  129. }
  130. /**
  131. * Returns the inclusion filters defined by this class for the requested $object
  132. * @param string $object The object to get inclusions for (dir|db)
  133. * @return array The inclusion filters
  134. */
  135. public final function &getInclusions($object)
  136. {
  137. if( ($this->subtype != 'inclusion') || ($this->object != $object) )
  138. {
  139. $dummy = array();
  140. return $dummy;
  141. }
  142. switch($this->method)
  143. {
  144. case 'api':
  145. return $this->get_inclusions_by_api();
  146. break;
  147. case 'direct':
  148. // Get a local reference of the filter data, if necessary
  149. if(is_null($this->filter_data))
  150. {
  151. $filters =& AEFactory::getFilters();
  152. $this->filter_data =& $filters->getFilterData($this->filter_name);
  153. }
  154. return $this->filter_data;
  155. break;
  156. default:
  157. // regex inclusion is not supported at the moment
  158. $dummy = array();
  159. return $dummy;
  160. break;
  161. }
  162. }
  163. /**
  164. * Adds an exclusion filter, or add/replace an inclusion filter
  165. * @param string $root Filter's root
  166. * @param mixed $test Exclusion: the filter string. Inclusion: the root definition data
  167. * @return bool True on success
  168. */
  169. public final function set($root, $test)
  170. {
  171. if( in_array($this->subtype, array('all','content','children')) )
  172. {
  173. return $this->setExclusion($root, $test);
  174. }
  175. else
  176. {
  177. return $this->setInclusion($root, $test);
  178. }
  179. }
  180. /**
  181. * Sets a filter, for direct and regex exclusion filter types
  182. * @param string $root The filter root object
  183. * @param string $test The filter string to set
  184. * @return bool True on success
  185. */
  186. private final function setExclusion($root, $test)
  187. {
  188. switch($this->method)
  189. {
  190. default:
  191. case 'api':
  192. // we can't set new filter elements for API-type filters
  193. return false;
  194. break;
  195. case 'direct':
  196. case 'regex':
  197. // Get a local reference of the filter data, if necessary
  198. if(is_null($this->filter_data))
  199. {
  200. $filters =& AEFactory::getFilters();
  201. $this->filter_data =& $filters->getFilterData($this->filter_name);
  202. }
  203. // Direct filters
  204. if(array_key_exists($root, $this->filter_data))
  205. {
  206. if( !in_array($test, $this->filter_data[$root]) )
  207. {
  208. $this->filter_data[$root][] = $test;
  209. }
  210. else
  211. {
  212. return false;
  213. }
  214. }
  215. else
  216. {
  217. $this->filter_data[$root] = array($test);
  218. }
  219. break;
  220. }
  221. $filters =& AEFactory::getFilters();
  222. $filters->setFilterData($this->filter_name, $this->filter_data);
  223. return true;
  224. }
  225. /**
  226. * Sets a filter, for direct inclusion filter types
  227. * @param string $root The inclusion filter key (root)
  228. * @param string $test The inclusion filter raw data
  229. * @return bool True on success
  230. */
  231. private final function setInclusion($root, $test)
  232. {
  233. switch($this->method)
  234. {
  235. default:
  236. case 'api':
  237. case 'regex':
  238. // we can't set new filter elements for API or regex type filters
  239. return false;
  240. break;
  241. case 'direct':
  242. // Get a local reference of the filter data, if necessary
  243. if(is_null($this->filter_data))
  244. {
  245. $filters =& AEFactory::getFilters();
  246. $this->filter_data =& $filters->getFilterData($this->filter_name);
  247. }
  248. $this->filter_data[$root] = $test;
  249. break;
  250. }
  251. $filters =& AEFactory::getFilters();
  252. $filters->setFilterData($this->filter_name, $this->filter_data);
  253. return true;
  254. }
  255. /**
  256. * Unsets a given filter
  257. * @param string $root Filter's root
  258. * @param string $test The filter to remove
  259. */
  260. public final function remove($root, $test = null)
  261. {
  262. if($this->subtype == 'inclusion')
  263. {
  264. return $this->removeInclusion($root);
  265. }
  266. else
  267. {
  268. return $this->removeExclusion($root, $test);
  269. }
  270. }
  271. /**
  272. * Completely removes all filters off a specific root
  273. * @param string $root
  274. */
  275. public final function reset($root)
  276. {
  277. switch($this->method)
  278. {
  279. default:
  280. case 'api':
  281. return false;
  282. break;
  283. case 'direct':
  284. case 'regex':
  285. // Get a local reference of the filter data, if necessary
  286. if(is_null($this->filter_data))
  287. {
  288. $filters =& AEFactory::getFilters();
  289. $this->filter_data =& $filters->getFilterData($this->filter_name);
  290. }
  291. // Direct filters
  292. if(array_key_exists($root, $this->filter_data))
  293. {
  294. unset($this->filter_data[$root]);
  295. }
  296. else
  297. {
  298. // Root not found
  299. return false;
  300. }
  301. break;
  302. }
  303. $filters =& AEFactory::getFilters();
  304. $filters->setFilterData($this->filter_name, $this->filter_data);
  305. return true;
  306. }
  307. /**
  308. * Remove a key from direct and regex filters
  309. * @param string $root The filter root object
  310. * @param string $test The filter string to set
  311. * @return bool True on success
  312. */
  313. private final function removeExclusion($root, $test)
  314. {
  315. switch($this->method)
  316. {
  317. default:
  318. case 'api':
  319. // we can't remove filter elements from API-type filters
  320. return false;
  321. break;
  322. case 'direct':
  323. case 'regex':
  324. // Get a local reference of the filter data, if necessary
  325. if(is_null($this->filter_data))
  326. {
  327. $filters =& AEFactory::getFilters();
  328. $this->filter_data =& $filters->getFilterData($this->filter_name);
  329. }
  330. // Direct filters
  331. if(array_key_exists($root, $this->filter_data))
  332. {
  333. if( in_array($test, $this->filter_data[$root]) )
  334. {
  335. if(count($this->filter_data[$root]) == 1)
  336. {
  337. // If it's the only element, remove the entire root key
  338. unset($this->filter_data[$root]);
  339. }
  340. else
  341. {
  342. // If there are more elements, remove just the $test value
  343. $key = array_search($test, $this->filter_data[$root]);
  344. unset($this->filter_data[$root][$key]);
  345. }
  346. }
  347. else
  348. {
  349. // Filter object not found
  350. return false;
  351. }
  352. }
  353. else
  354. {
  355. // Root not found
  356. return false;
  357. }
  358. break;
  359. }
  360. $filters =& AEFactory::getFilters();
  361. $filters->setFilterData($this->filter_name, $this->filter_data);
  362. return true;
  363. }
  364. /**
  365. * Remove an inclusion filter
  366. * @param string $root The root of the filter to remove
  367. * @return bool
  368. */
  369. private final function removeInclusion($root)
  370. {
  371. switch($this->method)
  372. {
  373. default:
  374. case 'api':
  375. case 'regex':
  376. // we can't remove filter elements from API or regex type filters
  377. return false;
  378. break;
  379. case 'direct':
  380. // Get a local reference of the filter data, if necessary
  381. if(is_null($this->filter_data))
  382. {
  383. $filters =& AEFactory::getFilters();
  384. $this->filter_data =& $filters->getFilterData($this->filter_name);
  385. }
  386. if(array_key_exists($root, $this->filter_data))
  387. {
  388. unset($this->filter_data[$root]);
  389. }
  390. else
  391. {
  392. // Root not found
  393. return false;
  394. }
  395. break;
  396. }
  397. $filters =& AEFactory::getFilters();
  398. $filters->setFilterData($this->filter_name, $this->filter_data);
  399. return true;
  400. }
  401. /**
  402. * Toggles a filter
  403. * @param string $root The filter root object
  404. * @param string $test The filter string to toggle
  405. * @param bool $new_status The new filter status after the operation (true: enabled, false: disabled)
  406. * @return bool True on successful change, false if we failed to change it
  407. */
  408. public final function toggle($root, $test, &$new_status)
  409. {
  410. // Can't toggle inclusion filters!
  411. if( $this->subtype == 'inclusion' ) return false;
  412. $is_set = $this->isFiltered($test, $root, $this->object, $this->subtype);
  413. $new_status = !$is_set;
  414. if($is_set)
  415. {
  416. $status = $this->remove($root, $test);
  417. }
  418. else
  419. {
  420. $status = $this->set($root, $test);
  421. }
  422. if(!$status) $new_status = $is_set;
  423. return $status;
  424. }
  425. /**
  426. * Does this class has any filters? If it doesn't, its methods are never called by
  427. * Akeeba's engine to speed things up.
  428. * @return bool
  429. */
  430. public function hasFilters()
  431. {
  432. switch($this->method)
  433. {
  434. default:
  435. case 'api':
  436. // API filters always have data!
  437. return true;
  438. break;
  439. case 'direct':
  440. case 'regex':
  441. // Get a local reference of the filter data, if necessary
  442. if(is_null($this->filter_data))
  443. {
  444. $filters =& AEFactory::getFilters();
  445. $this->filter_data =& $filters->getFilterData($this->filter_name);
  446. }
  447. return !empty($this->filter_data);
  448. break;
  449. }
  450. }
  451. /**
  452. * Returns a list of filter strings for the given root. Used by MySQLDump engine.
  453. * @param string $root
  454. * @return array
  455. */
  456. public final function getFilters($root)
  457. {
  458. $dummy = array();
  459. switch($this->method)
  460. {
  461. default:
  462. case 'api':
  463. // API filters never have a list
  464. return $dummy;
  465. break;
  466. case 'direct':
  467. case 'regex':
  468. // Get a local reference of the filter data, if necessary
  469. if(is_null($this->filter_data))
  470. {
  471. $filters =& AEFactory::getFilters();
  472. $this->filter_data =& $filters->getFilterData($this->filter_name);
  473. }
  474. if(is_null($root))
  475. {
  476. // When NULL is passed as the root, we return all roots
  477. return $this->filter_data;
  478. }
  479. elseif(array_key_exists($root, $this->filter_data))
  480. {
  481. // The root exists, return its data
  482. return $this->filter_data[$root];
  483. }
  484. else
  485. {
  486. // The root doesn't exist, return an empty array
  487. return $dummy;
  488. }
  489. break;
  490. }
  491. }
  492. }