1: <?php
2:
3: /**
4: * See the enclosed file license.txt for licensing information.
5: * If you did not receive this file, get it at https://www.gnu.org/licenses/gpl-2.0.html
6: *
7: * @copyright (c) 2000-2016 XOOPS Project (www.xoops.org)
8: * @license GNU GPL 2.0 or later (https://www.gnu.org/licenses/gpl-2.0.html)
9: * @package installer
10: * @since 2.3.0
11: * @author Haruki Setoyama <haruki@planewave.org>
12: * @author Kazumi Ono <webmaster@myweb.ne.jp>
13: * @author Skalpa Keo <skalpa@xoops.org>
14: * @author Taiwen Jiang <phppp@users.sourceforge.net>
15: * @author DuGris (aka L. JEN) <dugris@frxoops.org>
16: **/
17: class PathStuffController
18: {
19: /**
20: * @var array
21: */
22: public $xoopsPath = array(
23: 'root' => '',
24: 'data' => '',
25: 'lib' => '',
26: );
27: /**
28: * @var array
29: */
30: public $xoopsPathDefault = array(
31: 'data' => 'xoops_data',
32: 'lib' => 'xoops_lib',
33: );
34: /**
35: * @var array
36: */
37: public $dataPath = array(
38: 'caches' => array(
39: 'smarty_cache',
40: 'smarty_compile',
41: 'xoops_cache',
42: ),
43: 'configs' => array(
44: 'captcha',
45: 'textsanitizer',
46: ),
47: 'data' => null,
48: 'protector' => null,
49: );
50: /**
51: * @var array
52: */
53: public $path_lookup = array(
54: 'root' => 'ROOT_PATH',
55: 'data' => 'VAR_PATH',
56: 'lib' => 'PATH',
57: );
58: public $xoopsUrl = '';
59: public $xoopsCookieDomain = '';
60: /**
61: * @var array
62: */
63: public $validPath = array(
64: 'root' => 0,
65: 'data' => 0,
66: 'lib' => 0,
67: );
68: /**
69: * @var bool
70: */
71: public $validUrl = false;
72: /**
73: * @var array
74: */
75: public $permErrors = array(
76: 'root' => null,
77: 'data' => null,
78: );
79:
80: /**
81: * @param $xoopsPathDefault
82: * @param $dataPath
83: */
84: public function __construct($xoopsPathDefault, $dataPath)
85: {
86: $this->xoopsPathDefault = $xoopsPathDefault;
87: $this->dataPath = $dataPath;
88:
89: if (isset($_SESSION['settings']['ROOT_PATH'])) {
90: foreach ($this->path_lookup as $req => $sess) {
91: $this->xoopsPath[$req] = $_SESSION['settings'][$sess];
92: }
93: } else {
94: $path = str_replace("\\", '/', realpath(dirname(dirname(__DIR__)) . '/'));
95: if (substr($path, -1) === '/') {
96: $path = substr($path, 0, -1);
97: }
98: if (file_exists("$path/mainfile.dist.php")) {
99: $this->xoopsPath['root'] = $path;
100: }
101: // Firstly, locate XOOPS lib folder out of XOOPS root folder
102: $this->xoopsPath['lib'] = dirname($path) . '/' . $this->xoopsPathDefault['lib'];
103: // If the folder is not created, re-locate XOOPS lib folder inside XOOPS root folder
104: if (!is_dir($this->xoopsPath['lib'] . '/')) {
105: $this->xoopsPath['lib'] = $path . '/' . $this->xoopsPathDefault['lib'];
106: }
107: // Firstly, locate XOOPS data folder out of XOOPS root folder
108: $this->xoopsPath['data'] = dirname($path) . '/' . $this->xoopsPathDefault['data'];
109: // If the folder is not created, re-locate XOOPS data folder inside XOOPS root folder
110: if (!is_dir($this->xoopsPath['data'] . '/')) {
111: $this->xoopsPath['data'] = $path . '/' . $this->xoopsPathDefault['data'];
112: }
113: }
114: if (isset($_SESSION['settings']['URL'])) {
115: $this->xoopsUrl = $_SESSION['settings']['URL'];
116: } else {
117: $path = $GLOBALS['wizard']->baseLocation();
118: $this->xoopsUrl = substr($path, 0, strrpos($path, '/'));
119: }
120: if (isset($_SESSION['settings']['COOKIE_DOMAIN'])) {
121: $this->xoopsCookieDomain = $_SESSION['settings']['COOKIE_DOMAIN'];
122: } else {
123: $this->xoopsCookieDomain = xoops_getBaseDomain($this->xoopsUrl);
124: }
125: }
126:
127: public function execute()
128: {
129: $this->readRequest();
130: $valid = $this->validate();
131: if ($_SERVER['REQUEST_METHOD'] === 'POST') {
132: foreach ($this->path_lookup as $req => $sess) {
133: $_SESSION['settings'][$sess] = $this->xoopsPath[$req];
134: }
135: $_SESSION['settings']['URL'] = $this->xoopsUrl;
136: $_SESSION['settings']['COOKIE_DOMAIN'] = $this->xoopsCookieDomain;
137: if ($valid) {
138: $GLOBALS['wizard']->redirectToPage('+1');
139: } else {
140: $GLOBALS['wizard']->redirectToPage('+0');
141: }
142: }
143: }
144:
145: public function readRequest()
146: {
147: if ($_SERVER['REQUEST_METHOD'] === 'POST') {
148: $request = $_POST;
149: foreach ($this->path_lookup as $req => $sess) {
150: if (isset($request[$req])) {
151: $request[$req] = str_replace("\\", '/', trim($request[$req]));
152: if (substr($request[$req], -1) === '/') {
153: $request[$req] = substr($request[$req], 0, -1);
154: }
155: $this->xoopsPath[$req] = $request[$req];
156: }
157: }
158: if (isset($request['URL'])) {
159: $request['URL'] = trim($request['URL']);
160: if (substr($request['URL'], -1) === '/') {
161: $request['URL'] = substr($request['URL'], 0, -1);
162: }
163: $this->xoopsUrl = $request['URL'];
164: }
165: if (isset($request['COOKIE_DOMAIN'])) {
166: $tempCookieDomain = trim($request['COOKIE_DOMAIN']);
167: $tempParts = parse_url($tempCookieDomain);
168: if (!empty($tempParts['host'])) {
169: $tempCookieDomain = $tempParts['host'];
170: }
171: $request['COOKIE_DOMAIN'] = $tempCookieDomain;
172: $this->xoopsCookieDomain = $tempCookieDomain;
173: }
174: }
175: }
176:
177: /**
178: * @return bool
179: */
180: public function validate()
181: {
182: foreach (array_keys($this->xoopsPath) as $path) {
183: if ($this->checkPath($path)) {
184: $this->checkPermissions($path);
185: }
186: }
187: $this->validUrl = !empty($this->xoopsUrl);
188: $validPaths = (array_sum(array_values($this->validPath)) == count(array_keys($this->validPath))) ? 1 : 0;
189: $validPerms = true;
190: foreach ($this->permErrors as $key => $errs) {
191: if (empty($errs)) {
192: continue;
193: }
194: foreach ($errs as $path => $status) {
195: if (empty($status)) {
196: $validPerms = false;
197: break;
198: }
199: }
200: }
201:
202: return ($validPaths && $this->validUrl && $validPerms);
203: }
204:
205: /**
206: * @param string $PATH
207: *
208: * @return int
209: */
210: public function checkPath($PATH = '')
211: {
212: $ret = 1;
213: if ($PATH === 'root' || empty($PATH)) {
214: $path = 'root';
215: if (is_dir($this->xoopsPath[$path]) && is_readable($this->xoopsPath[$path])) {
216: @include_once "{$this->xoopsPath[$path]}/include/version.php";
217: if (file_exists("{$this->xoopsPath[$path]}/mainfile.dist.php") && defined('XOOPS_VERSION')) {
218: $this->validPath[$path] = 1;
219: }
220: }
221: $ret *= $this->validPath[$path];
222: }
223: if ($PATH === 'lib' || empty($PATH)) {
224: $path = 'lib';
225: if (is_dir($this->xoopsPath[$path]) && is_readable($this->xoopsPath[$path])) {
226: $this->validPath[$path] = 1;
227: }
228: $ret *= $this->validPath[$path];
229: }
230: if ($PATH === 'data' || empty($PATH)) {
231: $path = 'data';
232: if (is_dir($this->xoopsPath[$path]) && is_readable($this->xoopsPath[$path])) {
233: $this->validPath[$path] = 1;
234: }
235: $ret *= $this->validPath[$path];
236: }
237:
238: return $ret;
239: }
240:
241: /**
242: * @param $parent
243: * @param $path
244: * @param $error
245: * @return null
246: */
247: public function setPermission($parent, $path, &$error)
248: {
249: if (is_array($path)) {
250: foreach (array_keys($path) as $item) {
251: if (is_string($item)) {
252: $error[$parent . '/' . $item] = $this->makeWritable($parent . '/' . $item);
253: if (empty($path[$item])) {
254: continue;
255: }
256: foreach ($path[$item] as $child) {
257: $this->setPermission($parent . '/' . $item, $child, $error);
258: }
259: } else {
260: $error[$parent . '/' . $path[$item]] = $this->makeWritable($parent . '/' . $path[$item]);
261: }
262: }
263: } else {
264: $error[$parent . '/' . $path] = $this->makeWritable($parent . '/' . $path);
265: }
266:
267: return null;
268: }
269:
270: /**
271: * @param $path
272: *
273: * @return bool
274: */
275: public function checkPermissions($path)
276: {
277: $paths = array(
278: 'root' => array(
279: 'mainfile.php',
280: 'uploads',
281: ),
282: 'data' => $this->dataPath,
283: );
284: $errors = array(
285: 'root' => null,
286: 'data' => null,
287: );
288:
289: if (!isset($this->xoopsPath[$path])) {
290: return false;
291: }
292: if (!isset($errors[$path])) {
293: return true;
294: }
295: $this->setPermission($this->xoopsPath[$path], $paths[$path], $errors[$path]);
296: if (in_array(false, $errors[$path])) {
297: $this->permErrors[$path] = $errors[$path];
298: }
299:
300: return true;
301: }
302:
303: /**
304: * Write-enable the specified folder
305: *
306: * @param string $path
307: * @param bool $create
308: *
309: * @internal param bool $recurse
310: * @return false on failure, method (u-ser,g-roup,w-orld) on success
311: */
312: public function makeWritable($path, $create = true)
313: {
314: $mode = intval('0777', 8);
315: if (!is_dir($path)) {
316: if (!$create) {
317: return false;
318: } else {
319: mkdir($path, $mode);
320: }
321: }
322: if (!is_writable($path)) {
323: chmod($path, $mode);
324: }
325: clearstatcache();
326: if (is_writable($path)) {
327: $info = stat($path);
328: if ($info['mode'] & 0002) {
329: return 'w';
330: } elseif ($info['mode'] & 0020) {
331: return 'g';
332: }
333:
334: return 'u';
335: }
336:
337: return false;
338: }
339: }
340: