PageRenderTime 34ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/include/file_functions.php

https://gitlab.com/protoneutron/xbtbb3cker
PHP | 416 lines | 286 code | 57 blank | 73 comment | 80 complexity | 22782f9e0e63941e828c4a74ec5a2712 MD5 | raw file
  1. <?php
  2. /**
  3. *
  4. * @package xbtBB3cker
  5. * @copyright (c) 2015 PPK
  6. * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
  7. *
  8. */
  9. /**
  10. * @ignore
  11. */
  12. if (!defined('IN_PHPBB'))
  13. {
  14. exit;
  15. }
  16. //From /includes/constants.php
  17. define('CHMOD_ALL', 7);// - all permissions (7)
  18. define('CHMOD_READ', 4);// - read permission (4)
  19. define('CHMOD_WRITE', 2);// - write permission (2)
  20. define('CHMOD_EXECUTE', 1);// - execute permission (1)
  21. //From /includes/functions.php
  22. function phpbb_chmod($filename, $perms = CHMOD_READ)
  23. {
  24. static $_chmod_info;
  25. // Return if the file no longer exists.
  26. if (!file_exists($filename))
  27. {
  28. return false;
  29. }
  30. // Determine some common vars
  31. if (empty($_chmod_info))
  32. {
  33. if (!function_exists('fileowner') || !function_exists('filegroup'))
  34. {
  35. // No need to further determine owner/group - it is unknown
  36. $_chmod_info['process'] = false;
  37. }
  38. else
  39. {
  40. global $phpbb_root_path, $phpEx;
  41. // Determine owner/group of common.php file and the filename we want to change here
  42. $common_php_owner = @fileowner($phpbb_root_path . 'common.' . $phpEx);
  43. $common_php_group = @filegroup($phpbb_root_path . 'common.' . $phpEx);
  44. // And the owner and the groups PHP is running under.
  45. $php_uid = (function_exists('posix_getuid')) ? @posix_getuid() : false;
  46. $php_gids = (function_exists('posix_getgroups')) ? @posix_getgroups() : false;
  47. // If we are unable to get owner/group, then do not try to set them by guessing
  48. if (!$php_uid || empty($php_gids) || !$common_php_owner || !$common_php_group)
  49. {
  50. $_chmod_info['process'] = false;
  51. }
  52. else
  53. {
  54. $_chmod_info = array(
  55. 'process' => true,
  56. 'common_owner' => $common_php_owner,
  57. 'common_group' => $common_php_group,
  58. 'php_uid' => $php_uid,
  59. 'php_gids' => $php_gids,
  60. );
  61. }
  62. }
  63. }
  64. if ($_chmod_info['process'])
  65. {
  66. $file_uid = @fileowner($filename);
  67. $file_gid = @filegroup($filename);
  68. // Change owner
  69. if (@chown($filename, $_chmod_info['common_owner']))
  70. {
  71. clearstatcache();
  72. $file_uid = @fileowner($filename);
  73. }
  74. // Change group
  75. if (@chgrp($filename, $_chmod_info['common_group']))
  76. {
  77. clearstatcache();
  78. $file_gid = @filegroup($filename);
  79. }
  80. // If the file_uid/gid now match the one from common.php we can process further, else we are not able to change something
  81. if ($file_uid != $_chmod_info['common_owner'] || $file_gid != $_chmod_info['common_group'])
  82. {
  83. $_chmod_info['process'] = false;
  84. }
  85. }
  86. // Still able to process?
  87. if ($_chmod_info['process'])
  88. {
  89. if ($file_uid == $_chmod_info['php_uid'])
  90. {
  91. $php = 'owner';
  92. }
  93. else if (in_array($file_gid, $_chmod_info['php_gids']))
  94. {
  95. $php = 'group';
  96. }
  97. else
  98. {
  99. // Since we are setting the everyone bit anyway, no need to do expensive operations
  100. $_chmod_info['process'] = false;
  101. }
  102. }
  103. // We are not able to determine or change something
  104. if (!$_chmod_info['process'])
  105. {
  106. $php = 'other';
  107. }
  108. // Owner always has read/write permission
  109. $owner = CHMOD_READ | CHMOD_WRITE;
  110. if (is_dir($filename))
  111. {
  112. $owner |= CHMOD_EXECUTE;
  113. // Only add execute bit to the permission if the dir needs to be readable
  114. if ($perms & CHMOD_READ)
  115. {
  116. $perms |= CHMOD_EXECUTE;
  117. }
  118. }
  119. switch ($php)
  120. {
  121. case 'owner':
  122. $result = @chmod($filename, ($owner << 6) + (0 << 3) + (0 << 0));
  123. clearstatcache();
  124. if (is_readable($filename) && phpbb_is_writable($filename))
  125. {
  126. break;
  127. }
  128. case 'group':
  129. $result = @chmod($filename, ($owner << 6) + ($perms << 3) + (0 << 0));
  130. clearstatcache();
  131. if ((!($perms & CHMOD_READ) || is_readable($filename)) && (!($perms & CHMOD_WRITE) || phpbb_is_writable($filename)))
  132. {
  133. break;
  134. }
  135. case 'other':
  136. $result = @chmod($filename, ($owner << 6) + ($perms << 3) + ($perms << 0));
  137. clearstatcache();
  138. if ((!($perms & CHMOD_READ) || is_readable($filename)) && (!($perms & CHMOD_WRITE) || phpbb_is_writable($filename)))
  139. {
  140. break;
  141. }
  142. default:
  143. return false;
  144. break;
  145. }
  146. return $result;
  147. }
  148. function phpbb_is_writable($file)
  149. {
  150. if (strtolower(substr(PHP_OS, 0, 3)) === 'win' || !function_exists('is_writable'))
  151. {
  152. if (file_exists($file))
  153. {
  154. // Canonicalise path to absolute path
  155. $file = phpbb_realpath($file);
  156. if (is_dir($file))
  157. {
  158. // Test directory by creating a file inside the directory
  159. $result = @tempnam($file, 'i_w');
  160. if (is_string($result) && file_exists($result))
  161. {
  162. unlink($result);
  163. // Ensure the file is actually in the directory (returned realpathed)
  164. return (strpos($result, $file) === 0) ? true : false;
  165. }
  166. }
  167. else
  168. {
  169. $handle = @fopen($file, 'r+');
  170. if (is_resource($handle))
  171. {
  172. fclose($handle);
  173. return true;
  174. }
  175. }
  176. }
  177. else
  178. {
  179. // file does not exist test if we can write to the directory
  180. $dir = dirname($file);
  181. if (file_exists($dir) && is_dir($dir) && phpbb_is_writable($dir))
  182. {
  183. return true;
  184. }
  185. }
  186. return false;
  187. }
  188. else
  189. {
  190. return is_writable($file);
  191. }
  192. }
  193. function phpbb_own_realpath($path)
  194. {
  195. // Now to perform funky shizzle
  196. // Switch to use UNIX slashes
  197. $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
  198. $path_prefix = '';
  199. // Determine what sort of path we have
  200. if (is_absolute($path))
  201. {
  202. $absolute = true;
  203. if ($path[0] == '/')
  204. {
  205. // Absolute path, *NIX style
  206. $path_prefix = '';
  207. }
  208. else
  209. {
  210. // Absolute path, Windows style
  211. // Remove the drive letter and colon
  212. $path_prefix = $path[0] . ':';
  213. $path = substr($path, 2);
  214. }
  215. }
  216. else
  217. {
  218. // Relative Path
  219. // Prepend the current working directory
  220. if (function_exists('getcwd'))
  221. {
  222. // This is the best method, hopefully it is enabled!
  223. $path = str_replace(DIRECTORY_SEPARATOR, '/', getcwd()) . '/' . $path;
  224. $absolute = true;
  225. if (preg_match('#^[a-z]:#i', $path))
  226. {
  227. $path_prefix = $path[0] . ':';
  228. $path = substr($path, 2);
  229. }
  230. else
  231. {
  232. $path_prefix = '';
  233. }
  234. }
  235. else if (isset($_SERVER['SCRIPT_FILENAME']) && !empty($_SERVER['SCRIPT_FILENAME']))
  236. {
  237. // Warning: If chdir() has been used this will lie!
  238. // Warning: This has some problems sometime (CLI can create them easily)
  239. $path = str_replace(DIRECTORY_SEPARATOR, '/', dirname($_SERVER['SCRIPT_FILENAME'])) . '/' . $path;
  240. $absolute = true;
  241. $path_prefix = '';
  242. }
  243. else
  244. {
  245. // We have no way of getting the absolute path, just run on using relative ones.
  246. $absolute = false;
  247. $path_prefix = '.';
  248. }
  249. }
  250. // Remove any repeated slashes
  251. $path = preg_replace('#/{2,}#', '/', $path);
  252. // Remove the slashes from the start and end of the path
  253. $path = trim($path, '/');
  254. // Break the string into little bits for us to nibble on
  255. $bits = explode('/', $path);
  256. // Remove any . in the path, renumber array for the loop below
  257. $bits = array_values(array_diff($bits, array('.')));
  258. // Lets get looping, run over and resolve any .. (up directory)
  259. for ($i = 0, $max = count($bits); $i < $max; $i++)
  260. {
  261. // @todo Optimise
  262. if ($bits[$i] == '..' )
  263. {
  264. if (isset($bits[$i - 1]))
  265. {
  266. if ($bits[$i - 1] != '..')
  267. {
  268. // We found a .. and we are able to traverse upwards, lets do it!
  269. unset($bits[$i]);
  270. unset($bits[$i - 1]);
  271. $i -= 2;
  272. $max -= 2;
  273. $bits = array_values($bits);
  274. }
  275. }
  276. else if ($absolute) // ie. !isset($bits[$i - 1]) && $absolute
  277. {
  278. // We have an absolute path trying to descend above the root of the filesystem
  279. // ... Error!
  280. return false;
  281. }
  282. }
  283. }
  284. // Prepend the path prefix
  285. array_unshift($bits, $path_prefix);
  286. $resolved = '';
  287. $max = count($bits) - 1;
  288. // Check if we are able to resolve symlinks, Windows cannot.
  289. $symlink_resolve = (function_exists('readlink')) ? true : false;
  290. foreach ($bits as $i => $bit)
  291. {
  292. if (@is_dir("$resolved/$bit") || ($i == $max && @is_file("$resolved/$bit")))
  293. {
  294. // Path Exists
  295. if ($symlink_resolve && is_link("$resolved/$bit") && ($link = readlink("$resolved/$bit")))
  296. {
  297. // Resolved a symlink.
  298. $resolved = $link . (($i == $max) ? '' : '/');
  299. continue;
  300. }
  301. }
  302. else
  303. {
  304. // Something doesn't exist here!
  305. // This is correct realpath() behaviour but sadly open_basedir and safe_mode make this problematic
  306. // return false;
  307. }
  308. $resolved .= $bit . (($i == $max) ? '' : '/');
  309. }
  310. // @todo If the file exists fine and open_basedir only has one path we should be able to prepend it
  311. // because we must be inside that basedir, the question is where...
  312. // @internal The slash in is_dir() gets around an open_basedir restriction
  313. if (!@file_exists($resolved) || (!@is_dir($resolved . '/') && !is_file($resolved)))
  314. {
  315. return false;
  316. }
  317. // Put the slashes back to the native operating systems slashes
  318. $resolved = str_replace('/', DIRECTORY_SEPARATOR, $resolved);
  319. // Check for DIRECTORY_SEPARATOR at the end (and remove it!)
  320. if (substr($resolved, -1) == DIRECTORY_SEPARATOR)
  321. {
  322. return substr($resolved, 0, -1);
  323. }
  324. return $resolved; // We got here, in the end!
  325. }
  326. if (!function_exists('realpath'))
  327. {
  328. /**
  329. * A wrapper for realpath
  330. * @ignore
  331. */
  332. function phpbb_realpath($path)
  333. {
  334. return phpbb_own_realpath($path);
  335. }
  336. }
  337. else
  338. {
  339. /**
  340. * A wrapper for realpath
  341. */
  342. function phpbb_realpath($path)
  343. {
  344. $realpath = realpath($path);
  345. // Strangely there are provider not disabling realpath but returning strange values. :o
  346. // We at least try to cope with them.
  347. if ($realpath === $path || $realpath === false)
  348. {
  349. return phpbb_own_realpath($path);
  350. }
  351. // Check for DIRECTORY_SEPARATOR at the end (and remove it!)
  352. if (substr($realpath, -1) == DIRECTORY_SEPARATOR)
  353. {
  354. $realpath = substr($realpath, 0, -1);
  355. }
  356. return $realpath;
  357. }
  358. }
  359. ?>