/lib/Watchdog.php

https://github.com/Alex8452/Kurogo-Mobile-Web-Doc-Translation · PHP · 148 lines · 99 code · 26 blank · 23 comment · 23 complexity · fb285aa17cb8b82dca6a940510cd3598 MD5 · raw file

  1. <?php
  2. class Watchdog {
  3. private static $_instance = NULL;
  4. protected $workingRealpath = false;
  5. protected $kurogoPathDirs = array();
  6. protected $safePathDirs = array();
  7. protected $safePathREs = array();
  8. private function __clone() {}
  9. protected function __construct() {
  10. // realpath returns true if the directory exists even if the file doesn't on PHP < 5.3
  11. $this->workingRealpath = version_compare(PHP_VERSION, '5.3.0') >= 0;
  12. }
  13. //
  14. // Internal implementation of functions to generate lists and
  15. // regular expressions describing acceptable file paths
  16. //
  17. protected function _getKurogoPathDirs() {
  18. if (!$this->kurogoPathDirs) {
  19. $rootDir = realpath(ROOT_DIR).DIRECTORY_SEPARATOR;
  20. if (!defined('SITE_DIR')) {
  21. return array($rootDir); // SiteConfig has not initialized yet
  22. }
  23. $this->kurogoPathDirs = array($rootDir);
  24. $siteDir = realpath(SITE_DIR).DIRECTORY_SEPARATOR;
  25. if (strncmp($siteDir, $rootDir, strlen($rootDir)) != 0) {
  26. $this->kurogoPathDirs[] = $siteDir;
  27. }
  28. // support for future feature to allow cache to be moved to a fast disk
  29. $cacheDir = realpath(CACHE_DIR).DIRECTORY_SEPARATOR;
  30. if (strncmp($cacheDir, $rootDir, strlen($rootDir)) != 0) {
  31. $this->kurogoPathDirs[] = $cacheDir;
  32. }
  33. //error_log('Kurogo files: '.print_r($this->kurogoPathDirs, true));
  34. }
  35. return $this->kurogoPathDirs;
  36. }
  37. protected function _getSafePathDirs() {
  38. if (!$this->safePathDirs && defined('SITE_DIR')) {
  39. $this->safePathDirs = array(
  40. realpath(SITE_DIR).DIRECTORY_SEPARATOR.'media'.DIRECTORY_SEPARATOR,
  41. realpath(CACHE_DIR).DIRECTORY_SEPARATOR.'FileLoader'.DIRECTORY_SEPARATOR,
  42. );
  43. //error_log('Safe files: '.print_r($this->safePathDirs, true));
  44. }
  45. return $this->safePathDirs;
  46. }
  47. protected function _getSafePathREs() {
  48. if (!$this->safePathREs && defined('SITE_DIR') && defined('THEME_DIR')) {
  49. $delimiter = ';';
  50. $this->safePathREs = array(
  51. $delimiter.
  52. '^('.preg_quote(realpath(THEME_DIR), $delimiter).'|'.
  53. preg_quote(realpath(SITE_DIR).DIRECTORY_SEPARATOR, $delimiter).'app|'.
  54. preg_quote(realpath(ROOT_DIR).DIRECTORY_SEPARATOR, $delimiter).'app)'.
  55. preg_quote(DIRECTORY_SEPARATOR, $delimiter).
  56. '(common|modules'.preg_quote(DIRECTORY_SEPARATOR, $delimiter).'[^'.preg_quote(DIRECTORY_SEPARATOR, $delimiter).']+)'.
  57. preg_quote(DIRECTORY_SEPARATOR, $delimiter).
  58. '(css|images|javascript)'.
  59. preg_quote(DIRECTORY_SEPARATOR, $delimiter).
  60. $delimiter,
  61. );
  62. //error_log('Safe REs: '.print_r($this->safePathREs, true));
  63. }
  64. return $this->safePathREs;
  65. }
  66. //
  67. // Internal implementation of path checking functions
  68. //
  69. protected function _safePath($path) {
  70. // realpath_exists calls Watchdog::kurogoPath()
  71. $test = realpath($path);
  72. if ($test && ($this->workingRealpath || file_exists($test))) {
  73. // Check safe directories first because strncmp is fast
  74. foreach ($this->_getSafePathDirs() as $dir) {
  75. if (strncmp($test, $dir, strlen($dir)) == 0) {
  76. return $test;
  77. }
  78. }
  79. foreach ($this->_getSafePathREs() as $re) {
  80. if (preg_match($re, $test)) {
  81. return $test;
  82. }
  83. }
  84. error_log("WARNING! Blocking attempt from ".$_SERVER['REMOTE_ADDR']." to access unsafe path '$test'");
  85. }
  86. // path is invalid or refers to an unsafe file
  87. return false;
  88. }
  89. protected function _kurogoPath($path) {
  90. // realpath_exists calls Watchdog::kurogoPath()
  91. $test = realpath($path);
  92. if ($test && ($this->workingRealpath || file_exists($test))) {
  93. foreach ($this->_getKurogoPathDirs() as $dir) {
  94. if (strncmp($test, $dir, strlen($dir)) == 0) {
  95. return $test;
  96. }
  97. }
  98. error_log("WARNING! Blocking attempt from ".$_SERVER['REMOTE_ADDR']." to access non-Kurogo path '$test'");
  99. }
  100. // path is invalid or outside Kurogo directories
  101. return false;
  102. }
  103. //
  104. // Shared instance of Watchdog class
  105. //
  106. protected static function sharedInstance() {
  107. if (!isset(self::$_instance)) {
  108. $c = __CLASS__;
  109. self::$_instance = new $c;
  110. }
  111. return self::$_instance;
  112. }
  113. //
  114. // Public static helper functions
  115. //
  116. public static function safePath($path) {
  117. return self::sharedInstance()->_safePath($path);
  118. }
  119. public static function kurogoPath($path) {
  120. return self::sharedInstance()->_kurogoPath($path);
  121. }
  122. }