Mercurial > hg > vamp-website
comparison forum/Sources/Packages.php @ 76:e3e11437ecea website
Add forum code
author | Chris Cannam |
---|---|
date | Sun, 07 Jul 2013 11:25:48 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
75:72f59aa7e503 | 76:e3e11437ecea |
---|---|
1 <?php | |
2 | |
3 /** | |
4 * Simple Machines Forum (SMF) | |
5 * | |
6 * @package SMF | |
7 * @author Simple Machines http://www.simplemachines.org | |
8 * @copyright 2011 Simple Machines | |
9 * @license http://www.simplemachines.org/about/smf/license.php BSD | |
10 * | |
11 * @version 2.0.2 | |
12 */ | |
13 | |
14 if (!defined('SMF')) | |
15 die('Hacking attempt...'); | |
16 | |
17 /* // !!! | |
18 | |
19 void Packages() | |
20 // !!! | |
21 | |
22 void PackageInstallTest() | |
23 // !!! | |
24 | |
25 void PackageInstall() | |
26 // !!! | |
27 | |
28 void PackageList() | |
29 // !!! | |
30 | |
31 void ExamineFile() | |
32 // !!! | |
33 | |
34 void InstalledList() | |
35 // !!! | |
36 | |
37 void FlushInstall() | |
38 // !!! | |
39 | |
40 void PackageRemove() | |
41 // !!! | |
42 | |
43 void PackageBrowse() | |
44 // !!! | |
45 | |
46 void PackageOptions() | |
47 // !!! | |
48 | |
49 void ViewOperations() | |
50 // !!! | |
51 */ | |
52 | |
53 // This is the notoriously defunct package manager..... :/. | |
54 function Packages() | |
55 { | |
56 global $txt, $scripturl, $sourcedir, $context; | |
57 | |
58 //!!! Remove this! | |
59 if (isset($_GET['get']) || isset($_GET['pgdownload'])) | |
60 { | |
61 require_once($sourcedir . '/PackageGet.php'); | |
62 return PackageGet(); | |
63 } | |
64 | |
65 isAllowedTo('admin_forum'); | |
66 | |
67 // Load all the basic stuff. | |
68 require_once($sourcedir . '/Subs-Package.php'); | |
69 loadLanguage('Packages'); | |
70 loadTemplate('Packages', 'admin'); | |
71 | |
72 $context['page_title'] = $txt['package']; | |
73 | |
74 // Delegation makes the world... that is, the package manager go 'round. | |
75 $subActions = array( | |
76 'browse' => 'PackageBrowse', | |
77 'remove' => 'PackageRemove', | |
78 'list' => 'PackageList', | |
79 'ftptest' => 'PackageFTPTest', | |
80 'install' => 'PackageInstallTest', | |
81 'install2' => 'PackageInstall', | |
82 'uninstall' => 'PackageInstallTest', | |
83 'uninstall2' => 'PackageInstall', | |
84 'installed' => 'InstalledList', | |
85 'options' => 'PackageOptions', | |
86 'perms' => 'PackagePermissions', | |
87 'flush' => 'FlushInstall', | |
88 'examine' => 'ExamineFile', | |
89 'showoperations' => 'ViewOperations', | |
90 ); | |
91 | |
92 // Work out exactly who it is we are calling. | |
93 if (isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']])) | |
94 $context['sub_action'] = $_REQUEST['sa']; | |
95 else | |
96 $context['sub_action'] = 'browse'; | |
97 | |
98 // Set up some tabs... | |
99 $context[$context['admin_menu_name']]['tab_data'] = array( | |
100 'title' => $txt['package_manager'], | |
101 // !!! 'help' => 'registrations', | |
102 'description' => $txt['package_manager_desc'], | |
103 'tabs' => array( | |
104 'browse' => array( | |
105 ), | |
106 'packageget' => array( | |
107 'description' => $txt['download_packages_desc'], | |
108 ), | |
109 'installed' => array( | |
110 'description' => $txt['installed_packages_desc'], | |
111 ), | |
112 'perms' => array( | |
113 'description' => $txt['package_file_perms_desc'], | |
114 ), | |
115 'options' => array( | |
116 'description' => $txt['package_install_options_ftp_why'], | |
117 ), | |
118 ), | |
119 ); | |
120 | |
121 // Call the function we're handing control to. | |
122 $subActions[$context['sub_action']](); | |
123 } | |
124 | |
125 // Test install a package. | |
126 function PackageInstallTest() | |
127 { | |
128 global $boarddir, $txt, $context, $scripturl, $sourcedir, $modSettings, $smcFunc, $settings; | |
129 | |
130 // You have to specify a file!! | |
131 if (!isset($_REQUEST['package']) || $_REQUEST['package'] == '') | |
132 redirectexit('action=admin;area=packages'); | |
133 $context['filename'] = preg_replace('~[\.]+~', '.', $_REQUEST['package']); | |
134 | |
135 // Do we have an existing id, for uninstalls and the like. | |
136 $context['install_id'] = isset($_REQUEST['pid']) ? (int) $_REQUEST['pid'] : 0; | |
137 | |
138 require_once($sourcedir . '/Subs-Package.php'); | |
139 | |
140 // Load up the package FTP information? | |
141 create_chmod_control(); | |
142 | |
143 // Make sure temp directory exists and is empty. | |
144 if (file_exists($boarddir . '/Packages/temp')) | |
145 deltree($boarddir . '/Packages/temp', false); | |
146 | |
147 if (!mktree($boarddir . '/Packages/temp', 0755)) | |
148 { | |
149 deltree($boarddir . '/Packages/temp', false); | |
150 if (!mktree($boarddir . '/Packages/temp', 0777)) | |
151 { | |
152 deltree($boarddir . '/Packages/temp', false); | |
153 create_chmod_control(array($boarddir . '/Packages/temp/delme.tmp'), array('destination_url' => $scripturl . '?action=admin;area=packages;sa=' . $_REQUEST['sa'] . ';package=' . $_REQUEST['package'], 'crash_on_error' => true)); | |
154 | |
155 deltree($boarddir . '/Packages/temp', false); | |
156 if (!mktree($boarddir . '/Packages/temp', 0777)) | |
157 fatal_lang_error('package_cant_download', false); | |
158 } | |
159 } | |
160 | |
161 $context['uninstalling'] = $_REQUEST['sa'] == 'uninstall'; | |
162 | |
163 // Change our last link tree item for more information on this Packages area. | |
164 $context['linktree'][count($context['linktree']) - 1] = array( | |
165 'url' => $scripturl . '?action=admin;area=packages;sa=browse', | |
166 'name' => $context['uninstalling'] ? $txt['package_uninstall_actions'] : $txt['install_actions'] | |
167 ); | |
168 $context['page_title'] .= ' - ' . ($context['uninstalling'] ? $txt['package_uninstall_actions'] : $txt['install_actions']); | |
169 | |
170 $context['sub_template'] = 'view_package'; | |
171 | |
172 if (!file_exists($boarddir . '/Packages/' . $context['filename'])) | |
173 { | |
174 deltree($boarddir . '/Packages/temp'); | |
175 fatal_lang_error('package_no_file', false); | |
176 } | |
177 | |
178 // Extract the files so we can get things like the readme, etc. | |
179 if (is_file($boarddir . '/Packages/' . $context['filename'])) | |
180 { | |
181 $context['extracted_files'] = read_tgz_file($boarddir . '/Packages/' . $context['filename'], $boarddir . '/Packages/temp'); | |
182 | |
183 if ($context['extracted_files'] && !file_exists($boarddir . '/Packages/temp/package-info.xml')) | |
184 foreach ($context['extracted_files'] as $file) | |
185 if (basename($file['filename']) == 'package-info.xml') | |
186 { | |
187 $context['base_path'] = dirname($file['filename']) . '/'; | |
188 break; | |
189 } | |
190 | |
191 if (!isset($context['base_path'])) | |
192 $context['base_path'] = ''; | |
193 } | |
194 elseif (is_dir($boarddir . '/Packages/' . $context['filename'])) | |
195 { | |
196 copytree($boarddir . '/Packages/' . $context['filename'], $boarddir . '/Packages/temp'); | |
197 $context['extracted_files'] = listtree($boarddir . '/Packages/temp'); | |
198 $context['base_path'] = ''; | |
199 } | |
200 else | |
201 fatal_lang_error('no_access', false); | |
202 | |
203 // Load up any custom themes we may want to install into... | |
204 $request = $smcFunc['db_query']('', ' | |
205 SELECT id_theme, variable, value | |
206 FROM {db_prefix}themes | |
207 WHERE (id_theme = {int:default_theme} OR id_theme IN ({array_int:known_theme_list})) | |
208 AND variable IN ({string:name}, {string:theme_dir})', | |
209 array( | |
210 'known_theme_list' => explode(',', $modSettings['knownThemes']), | |
211 'default_theme' => 1, | |
212 'name' => 'name', | |
213 'theme_dir' => 'theme_dir', | |
214 ) | |
215 ); | |
216 $theme_paths = array(); | |
217 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
218 $theme_paths[$row['id_theme']][$row['variable']] = $row['value']; | |
219 $smcFunc['db_free_result']($request); | |
220 | |
221 // Get the package info... | |
222 $packageInfo = getPackageInfo($context['filename']); | |
223 | |
224 if (!is_array($packageInfo)) | |
225 fatal_lang_error($packageInfo); | |
226 | |
227 $packageInfo['filename'] = $context['filename']; | |
228 $context['package_name'] = isset($packageInfo['name']) ? $packageInfo['name'] : $context['filename']; | |
229 | |
230 // Set the type of extraction... | |
231 $context['extract_type'] = isset($packageInfo['type']) ? $packageInfo['type'] : 'modification'; | |
232 | |
233 // The mod isn't installed.... unless proven otherwise. | |
234 $context['is_installed'] = false; | |
235 | |
236 // See if it is installed? | |
237 $request = $smcFunc['db_query']('', ' | |
238 SELECT version, themes_installed, db_changes | |
239 FROM {db_prefix}log_packages | |
240 WHERE package_id = {string:current_package} | |
241 AND install_state != {int:not_installed} | |
242 ORDER BY time_installed DESC | |
243 LIMIT 1', | |
244 array( | |
245 'not_installed' => 0, | |
246 'current_package' => $packageInfo['id'], | |
247 ) | |
248 ); | |
249 | |
250 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
251 { | |
252 $old_themes = explode(',', $row['themes_installed']); | |
253 $old_version = $row['version']; | |
254 $db_changes = empty($row['db_changes']) ? array() : unserialize($row['db_changes']); | |
255 } | |
256 $smcFunc['db_free_result']($request); | |
257 | |
258 $context['database_changes'] = array(); | |
259 if (!empty($db_changes)) | |
260 { | |
261 foreach ($db_changes as $change) | |
262 { | |
263 if (isset($change[2]) && isset($txt['package_db_' . $change[0]])) | |
264 $context['database_changes'][] = sprintf($txt['package_db_' . $change[0]], $change[1], $change[2]); | |
265 elseif (isset($txt['package_db_' . $change[0]])) | |
266 $context['database_changes'][] = sprintf($txt['package_db_' . $change[0]], $change[1]); | |
267 else | |
268 $context['database_changes'][] = $change[0] . '-' . $change[1] . (isset($change[2]) ? '-' . $change[2] : ''); | |
269 } | |
270 } | |
271 | |
272 // Uninstalling? | |
273 if ($context['uninstalling']) | |
274 { | |
275 // Wait, it's not installed yet! | |
276 if (!isset($old_version) && $context['uninstalling']) | |
277 { | |
278 deltree($boarddir . '/Packages/temp'); | |
279 fatal_lang_error('package_cant_uninstall', false); | |
280 } | |
281 | |
282 $actions = parsePackageInfo($packageInfo['xml'], true, 'uninstall'); | |
283 | |
284 // Gadzooks! There's no uninstaller at all!? | |
285 if (empty($actions)) | |
286 { | |
287 deltree($boarddir . '/Packages/temp'); | |
288 fatal_lang_error('package_uninstall_cannot', false); | |
289 } | |
290 | |
291 // Can't edit the custom themes it's edited if you're unisntalling, they must be removed. | |
292 $context['themes_locked'] = true; | |
293 | |
294 // Only let them uninstall themes it was installed into. | |
295 foreach ($theme_paths as $id => $data) | |
296 if ($id != 1 && !in_array($id, $old_themes)) | |
297 unset($theme_paths[$id]); | |
298 } | |
299 elseif (isset($old_version) && $old_version != $packageInfo['version']) | |
300 { | |
301 // Look for an upgrade... | |
302 $actions = parsePackageInfo($packageInfo['xml'], true, 'upgrade', $old_version); | |
303 | |
304 // There was no upgrade.... | |
305 if (empty($actions)) | |
306 $context['is_installed'] = true; | |
307 else | |
308 { | |
309 // Otherwise they can only upgrade themes from the first time around. | |
310 foreach ($theme_paths as $id => $data) | |
311 if ($id != 1 && !in_array($id, $old_themes)) | |
312 unset($theme_paths[$id]); | |
313 } | |
314 } | |
315 elseif (isset($old_version) && $old_version == $packageInfo['version']) | |
316 $context['is_installed'] = true; | |
317 | |
318 if (!isset($old_version) || $context['is_installed']) | |
319 $actions = parsePackageInfo($packageInfo['xml'], true, 'install'); | |
320 | |
321 $context['actions'] = array(); | |
322 $context['ftp_needed'] = false; | |
323 $context['has_failure'] = false; | |
324 $chmod_files = array(); | |
325 | |
326 if (empty($actions)) | |
327 return; | |
328 | |
329 // This will hold data about anything that can be installed in other themes. | |
330 $themeFinds = array( | |
331 'candidates' => array(), | |
332 'other_themes' => array(), | |
333 ); | |
334 | |
335 // Now prepare things for the template. | |
336 foreach ($actions as $action) | |
337 { | |
338 // Not failed until proven otherwise. | |
339 $failed = false; | |
340 | |
341 if ($action['type'] == 'chmod') | |
342 { | |
343 $chmod_files[] = $action['filename']; | |
344 continue; | |
345 } | |
346 elseif ($action['type'] == 'readme') | |
347 { | |
348 if (file_exists($boarddir . '/Packages/temp/' . $context['base_path'] . $action['filename'])) | |
349 $context['package_readme'] = htmlspecialchars(trim(file_get_contents($boarddir . '/Packages/temp/' . $context['base_path'] . $action['filename']), "\n\r")); | |
350 elseif (file_exists($action['filename'])) | |
351 $context['package_readme'] = htmlspecialchars(trim(file_get_contents($action['filename']), "\n\r")); | |
352 | |
353 if (!empty($action['parse_bbc'])) | |
354 { | |
355 require_once($sourcedir . '/Subs-Post.php'); | |
356 preparsecode($context['package_readme']); | |
357 $context['package_readme'] = parse_bbc($context['package_readme']); | |
358 } | |
359 else | |
360 $context['package_readme'] = nl2br($context['package_readme']); | |
361 | |
362 continue; | |
363 } | |
364 // Don't show redirects. | |
365 elseif ($action['type'] == 'redirect') | |
366 continue; | |
367 elseif ($action['type'] == 'error') | |
368 $context['has_failure'] = true; | |
369 elseif ($action['type'] == 'modification') | |
370 { | |
371 if (!file_exists($boarddir . '/Packages/temp/' . $context['base_path'] . $action['filename'])) | |
372 { | |
373 $context['has_failure'] = true; | |
374 | |
375 $context['actions'][] = array( | |
376 'type' => $txt['execute_modification'], | |
377 'action' => $smcFunc['htmlspecialchars'](strtr($action['filename'], array($boarddir => '.'))), | |
378 'description' => $txt['package_action_error'], | |
379 'failed' => true, | |
380 ); | |
381 } | |
382 | |
383 if ($action['boardmod']) | |
384 $mod_actions = parseBoardMod(@file_get_contents($boarddir . '/Packages/temp/' . $context['base_path'] . $action['filename']), true, $action['reverse'], $theme_paths); | |
385 else | |
386 $mod_actions = parseModification(@file_get_contents($boarddir . '/Packages/temp/' . $context['base_path'] . $action['filename']), true, $action['reverse'], $theme_paths); | |
387 | |
388 if (count($mod_actions) == 1 && isset($mod_actions[0]) && $mod_actions[0]['type'] == 'error' && $mod_actions[0]['filename'] == '-') | |
389 $mod_actions[0]['filename'] = $action['filename']; | |
390 | |
391 foreach ($mod_actions as $key => $mod_action) | |
392 { | |
393 // Lets get the last section of the file name. | |
394 if (isset($mod_action['filename']) && substr($mod_action['filename'], -13) != '.template.php') | |
395 $actual_filename = strtolower(substr(strrchr($mod_action['filename'], '/'), 1) . '||' . $action['filename']); | |
396 elseif (isset($mod_action['filename']) && preg_match('~([\w]*)/([\w]*)\.template\.php$~', $mod_action['filename'], $matches)) | |
397 $actual_filename = strtolower($matches[1] . '/' . $matches[2] . '.template.php' . '||' . $action['filename']); | |
398 else | |
399 $actual_filename = $key; | |
400 | |
401 if ($mod_action['type'] == 'opened') | |
402 $failed = false; | |
403 elseif ($mod_action['type'] == 'failure') | |
404 { | |
405 if (empty($mod_action['is_custom'])) | |
406 $context['has_failure'] = true; | |
407 $failed = true; | |
408 } | |
409 elseif ($mod_action['type'] == 'chmod') | |
410 { | |
411 $chmod_files[] = $mod_action['filename']; | |
412 } | |
413 elseif ($mod_action['type'] == 'saved') | |
414 { | |
415 if (!empty($mod_action['is_custom'])) | |
416 { | |
417 if (!isset($context['theme_actions'][$mod_action['is_custom']])) | |
418 $context['theme_actions'][$mod_action['is_custom']] = array( | |
419 'name' => $theme_paths[$mod_action['is_custom']]['name'], | |
420 'actions' => array(), | |
421 'has_failure' => $failed, | |
422 ); | |
423 else | |
424 $context['theme_actions'][$mod_action['is_custom']]['has_failure'] |= $failed; | |
425 | |
426 $context['theme_actions'][$mod_action['is_custom']]['actions'][$actual_filename] = array( | |
427 'type' => $txt['execute_modification'], | |
428 'action' => $smcFunc['htmlspecialchars'](strtr($mod_action['filename'], array($boarddir => '.'))), | |
429 'description' => $failed ? $txt['package_action_failure'] : $txt['package_action_success'], | |
430 'failed' => $failed, | |
431 ); | |
432 } | |
433 elseif (!isset($context['actions'][$actual_filename])) | |
434 { | |
435 $context['actions'][$actual_filename] = array( | |
436 'type' => $txt['execute_modification'], | |
437 'action' => $smcFunc['htmlspecialchars'](strtr($mod_action['filename'], array($boarddir => '.'))), | |
438 'description' => $failed ? $txt['package_action_failure'] : $txt['package_action_success'], | |
439 'failed' => $failed, | |
440 ); | |
441 } | |
442 else | |
443 { | |
444 $context['actions'][$actual_filename]['failed'] |= $failed; | |
445 $context['actions'][$actual_filename]['description'] = $context['actions'][$actual_filename]['failed'] ? $txt['package_action_failure'] : $txt['package_action_success']; | |
446 } | |
447 } | |
448 elseif ($mod_action['type'] == 'skipping') | |
449 { | |
450 $context['actions'][$actual_filename] = array( | |
451 'type' => $txt['execute_modification'], | |
452 'action' => $smcFunc['htmlspecialchars'](strtr($mod_action['filename'], array($boarddir => '.'))), | |
453 'description' => $txt['package_action_skipping'] | |
454 ); | |
455 } | |
456 elseif ($mod_action['type'] == 'missing' && empty($mod_action['is_custom'])) | |
457 { | |
458 $context['has_failure'] = true; | |
459 $context['actions'][$actual_filename] = array( | |
460 'type' => $txt['execute_modification'], | |
461 'action' => $smcFunc['htmlspecialchars'](strtr($mod_action['filename'], array($boarddir => '.'))), | |
462 'description' => $txt['package_action_missing'], | |
463 'failed' => true, | |
464 ); | |
465 } | |
466 elseif ($mod_action['type'] == 'error') | |
467 $context['actions'][$actual_filename] = array( | |
468 'type' => $txt['execute_modification'], | |
469 'action' => $smcFunc['htmlspecialchars'](strtr($mod_action['filename'], array($boarddir => '.'))), | |
470 'description' => $txt['package_action_error'], | |
471 'failed' => true, | |
472 ); | |
473 } | |
474 | |
475 // We need to loop again just to get the operations down correctly. | |
476 foreach ($mod_actions as $operation_key => $mod_action) | |
477 { | |
478 // Lets get the last section of the file name. | |
479 if (isset($mod_action['filename']) && substr($mod_action['filename'], -13) != '.template.php') | |
480 $actual_filename = strtolower(substr(strrchr($mod_action['filename'], '/'), 1) . '||' . $action['filename']); | |
481 elseif (isset($mod_action['filename']) && preg_match('~([\w]*)/([\w]*)\.template\.php$~', $mod_action['filename'], $matches)) | |
482 $actual_filename = strtolower($matches[1] . '/' . $matches[2] . '.template.php' . '||' . $action['filename']); | |
483 else | |
484 $actual_filename = $key; | |
485 | |
486 // We just need it for actual parse changes. | |
487 if (!in_array($mod_action['type'], array('error', 'result', 'opened', 'saved', 'end', 'missing', 'skipping', 'chmod'))) | |
488 { | |
489 if (empty($mod_action['is_custom'])) | |
490 $context['actions'][$actual_filename]['operations'][] = array( | |
491 'type' => $txt['execute_modification'], | |
492 'action' => $smcFunc['htmlspecialchars'](strtr($mod_action['filename'], array($boarddir => '.'))), | |
493 'description' => $mod_action['failed'] ? $txt['package_action_failure'] : $txt['package_action_success'], | |
494 'position' => $mod_action['position'], | |
495 'operation_key' => $operation_key, | |
496 'filename' => $action['filename'], | |
497 'is_boardmod' => $action['boardmod'], | |
498 'failed' => $mod_action['failed'], | |
499 'ignore_failure' => !empty($mod_action['ignore_failure']), | |
500 ); | |
501 | |
502 // Themes are under the saved type. | |
503 if (isset($mod_action['is_custom']) && isset($context['theme_actions'][$mod_action['is_custom']])) | |
504 $context['theme_actions'][$mod_action['is_custom']]['actions'][$actual_filename]['operations'][] = array( | |
505 'type' => $txt['execute_modification'], | |
506 'action' => $smcFunc['htmlspecialchars'](strtr($mod_action['filename'], array($boarddir => '.'))), | |
507 'description' => $mod_action['failed'] ? $txt['package_action_failure'] : $txt['package_action_success'], | |
508 'position' => $mod_action['position'], | |
509 'operation_key' => $operation_key, | |
510 'filename' => $action['filename'], | |
511 'is_boardmod' => $action['boardmod'], | |
512 'failed' => $mod_action['failed'], | |
513 'ignore_failure' => !empty($mod_action['ignore_failure']), | |
514 ); | |
515 } | |
516 } | |
517 | |
518 // Don't add anything else. | |
519 $thisAction = array(); | |
520 } | |
521 elseif ($action['type'] == 'code') | |
522 $thisAction = array( | |
523 'type' => $txt['execute_code'], | |
524 'action' => $smcFunc['htmlspecialchars']($action['filename']), | |
525 ); | |
526 elseif ($action['type'] == 'database') | |
527 { | |
528 $thisAction = array( | |
529 'type' => $txt['execute_database_changes'], | |
530 'action' => $smcFunc['htmlspecialchars']($action['filename']), | |
531 ); | |
532 } | |
533 elseif (in_array($action['type'], array('create-dir', 'create-file'))) | |
534 $thisAction = array( | |
535 'type' => $txt['package_create'] . ' ' . ($action['type'] == 'create-dir' ? $txt['package_tree'] : $txt['package_file']), | |
536 'action' => $smcFunc['htmlspecialchars'](strtr($action['destination'], array($boarddir => '.'))) | |
537 ); | |
538 elseif (in_array($action['type'], array('require-dir', 'require-file'))) | |
539 { | |
540 // Do this one... | |
541 $thisAction = array( | |
542 'type' => $txt['package_extract'] . ' ' . ($action['type'] == 'require-dir' ? $txt['package_tree'] : $txt['package_file']), | |
543 'action' => $smcFunc['htmlspecialchars'](strtr($action['destination'], array($boarddir => '.'))) | |
544 ); | |
545 | |
546 // Could this be theme related? | |
547 if (!empty($action['unparsed_destination']) && preg_match('~^\$(languagedir|languages_dir|imagesdir|themedir|themes_dir)~i', $action['unparsed_destination'], $matches)) | |
548 { | |
549 // Is the action already stated? | |
550 $theme_action = !empty($action['theme_action']) && in_array($action['theme_action'], array('no', 'yes', 'auto')) ? $action['theme_action'] : 'auto'; | |
551 // If it's not auto do we think we have something we can act upon? | |
552 if ($theme_action != 'auto' && !in_array($matches[1], array('languagedir', 'languages_dir', 'imagesdir', 'themedir'))) | |
553 $theme_action = ''; | |
554 // ... or if it's auto do we even want to do anything? | |
555 elseif ($theme_action == 'auto' && $matches[1] != 'imagesdir') | |
556 $theme_action = ''; | |
557 | |
558 // So, we still want to do something? | |
559 if ($theme_action != '') | |
560 $themeFinds['candidates'][] = $action; | |
561 // Otherwise is this is going into another theme record it. | |
562 elseif ($matches[1] == 'themes_dir') | |
563 $themeFinds['other_themes'][] = strtolower(strtr(parse_path($action['unparsed_destination']), array('\\' => '/')) . '/' . basename($action['filename'])); | |
564 } | |
565 } | |
566 elseif (in_array($action['type'], array('move-dir', 'move-file'))) | |
567 $thisAction = array( | |
568 'type' => $txt['package_move'] . ' ' . ($action['type'] == 'move-dir' ? $txt['package_tree'] : $txt['package_file']), | |
569 'action' => $smcFunc['htmlspecialchars'](strtr($action['source'], array($boarddir => '.'))) . ' => ' . $smcFunc['htmlspecialchars'](strtr($action['destination'], array($boarddir => '.'))) | |
570 ); | |
571 elseif (in_array($action['type'], array('remove-dir', 'remove-file'))) | |
572 { | |
573 $thisAction = array( | |
574 'type' => $txt['package_delete'] . ' ' . ($action['type'] == 'remove-dir' ? $txt['package_tree'] : $txt['package_file']), | |
575 'action' => $smcFunc['htmlspecialchars'](strtr($action['filename'], array($boarddir => '.'))) | |
576 ); | |
577 | |
578 // Could this be theme related? | |
579 if (!empty($action['unparsed_filename']) && preg_match('~^\$(languagedir|languages_dir|imagesdir|themedir|themes_dir)~i', $action['unparsed_filename'], $matches)) | |
580 { | |
581 | |
582 // Is the action already stated? | |
583 $theme_action = !empty($action['theme_action']) && in_array($action['theme_action'], array('no', 'yes', 'auto')) ? $action['theme_action'] : 'auto'; | |
584 $action['unparsed_destination'] = $action['unparsed_filename']; | |
585 // If it's not auto do we think we have something we can act upon? | |
586 if ($theme_action != 'auto' && !in_array($matches[1], array('languagedir', 'languages_dir', 'imagesdir', 'themedir'))) | |
587 $theme_action = ''; | |
588 // ... or if it's auto do we even want to do anything? | |
589 elseif ($theme_action == 'auto' && $matches[1] != 'imagesdir') | |
590 $theme_action = ''; | |
591 | |
592 // So, we still want to do something? | |
593 if ($theme_action != '') | |
594 $themeFinds['candidates'][] = $action; | |
595 // Otherwise is this is going into another theme record it. | |
596 elseif ($matches[1] == 'themes_dir') | |
597 $themeFinds['other_themes'][] = strtolower(strtr(parse_path($action['unparsed_filename']), array('\\' => '/')) . '/' . basename($action['filename'])); | |
598 } | |
599 } | |
600 | |
601 if (empty($thisAction)) | |
602 continue; | |
603 | |
604 // !!! None given? | |
605 $thisAction['description'] = isset($action['description']) ? $action['description'] : ''; | |
606 $context['actions'][] = $thisAction; | |
607 } | |
608 | |
609 // Have we got some things which we might want to do "multi-theme"? | |
610 if (!empty($themeFinds['candidates'])) | |
611 { | |
612 foreach ($themeFinds['candidates'] as $action_data) | |
613 { | |
614 // Get the part of the file we'll be dealing with. | |
615 preg_match('~^\$(languagedir|languages_dir|imagesdir|themedir)(\\|/)*(.+)*~i', $action_data['unparsed_destination'], $matches); | |
616 | |
617 if ($matches[1] == 'imagesdir') | |
618 $path = '/' . basename($settings['default_images_url']); | |
619 elseif ($matches[1] == 'languagedir' || $matches[1] == 'languages_dir') | |
620 $path = '/languages'; | |
621 else | |
622 $path = ''; | |
623 | |
624 if (!empty($matches[3])) | |
625 $path .= $matches[3]; | |
626 | |
627 if (!$context['uninstalling']) | |
628 $path .= '/' . basename($action_data['filename']); | |
629 | |
630 // Loop through each custom theme to note it's candidacy! | |
631 foreach ($theme_paths as $id => $theme_data) | |
632 { | |
633 if (isset($theme_data['theme_dir']) && $id != 1) | |
634 { | |
635 $real_path = $theme_data['theme_dir'] . $path; | |
636 // Confirm that we don't already have this dealt with by another entry. | |
637 if (!in_array(strtolower(strtr($real_path, array('\\' => '/'))), $themeFinds['other_themes'])) | |
638 { | |
639 // Check if we will need to chmod this. | |
640 if (!mktree(dirname($real_path), false)) | |
641 { | |
642 $temp = dirname($real_path); | |
643 while (!file_exists($temp) && strlen($temp) > 1) | |
644 $temp = dirname($temp); | |
645 $chmod_files[] = $temp; | |
646 } | |
647 if ($action_data['type'] == 'require-dir' && !is_writable($real_path) && (file_exists($real_path) || !is_writable(dirname($real_path)))) | |
648 $chmod_files[] = $real_path; | |
649 | |
650 if (!isset($context['theme_actions'][$id])) | |
651 $context['theme_actions'][$id] = array( | |
652 'name' => $theme_data['name'], | |
653 'actions' => array(), | |
654 ); | |
655 | |
656 if ($context['uninstalling']) | |
657 $context['theme_actions'][$id]['actions'][] = array( | |
658 'type' => $txt['package_delete'] . ' ' . ($action_data['type'] == 'require-dir' ? $txt['package_tree'] : $txt['package_file']), | |
659 'action' => strtr($real_path, array('\\' => '/', $boarddir => '.')), | |
660 'description' => '', | |
661 'value' => base64_encode(serialize(array('type' => $action_data['type'], 'orig' => $action_data['filename'], 'future' => $real_path, 'id' => $id))), | |
662 'not_mod' => true, | |
663 ); | |
664 else | |
665 $context['theme_actions'][$id]['actions'][] = array( | |
666 'type' => $txt['package_extract'] . ' ' . ($action_data['type'] == 'require-dir' ? $txt['package_tree'] : $txt['package_file']), | |
667 'action' => strtr($real_path, array('\\' => '/', $boarddir => '.')), | |
668 'description' => '', | |
669 'value' => base64_encode(serialize(array('type' => $action_data['type'], 'orig' => $action_data['destination'], 'future' => $real_path, 'id' => $id))), | |
670 'not_mod' => true, | |
671 ); | |
672 } | |
673 } | |
674 } | |
675 } | |
676 } | |
677 | |
678 // Trash the cache... which will also check permissions for us! | |
679 package_flush_cache(true); | |
680 | |
681 if (file_exists($boarddir . '/Packages/temp')) | |
682 deltree($boarddir . '/Packages/temp'); | |
683 | |
684 if (!empty($chmod_files)) | |
685 { | |
686 $ftp_status = create_chmod_control($chmod_files); | |
687 $context['ftp_needed'] = !empty($ftp_status['files']['notwritable']) && !empty($context['package_ftp']); | |
688 } | |
689 | |
690 checkSubmitOnce('register'); | |
691 } | |
692 | |
693 // Apply another type of (avatar, language, etc.) package. | |
694 function PackageInstall() | |
695 { | |
696 global $boarddir, $txt, $context, $boardurl, $scripturl, $sourcedir, $modSettings; | |
697 global $user_info, $smcFunc; | |
698 | |
699 // Make sure we don't install this mod twice. | |
700 checkSubmitOnce('check'); | |
701 checkSession(); | |
702 | |
703 // If there's no file, what are we installing? | |
704 if (!isset($_REQUEST['package']) || $_REQUEST['package'] == '') | |
705 redirectexit('action=admin;area=packages'); | |
706 $context['filename'] = $_REQUEST['package']; | |
707 | |
708 // If this is an uninstall, we'll have an id. | |
709 $context['install_id'] = isset($_REQUEST['pid']) ? (int) $_REQUEST['pid'] : 0; | |
710 | |
711 require_once($sourcedir . '/Subs-Package.php'); | |
712 | |
713 // !!! TODO: Perhaps do it in steps, if necessary? | |
714 | |
715 $context['uninstalling'] = $_REQUEST['sa'] == 'uninstall2'; | |
716 | |
717 // Set up the linktree for other. | |
718 $context['linktree'][count($context['linktree']) - 1] = array( | |
719 'url' => $scripturl . '?action=admin;area=packages;sa=browse', | |
720 'name' => $context['uninstalling'] ? $txt['uninstall'] : $txt['extracting'] | |
721 ); | |
722 $context['page_title'] .= ' - ' . ($context['uninstalling'] ? $txt['uninstall'] : $txt['extracting']); | |
723 | |
724 $context['sub_template'] = 'extract_package'; | |
725 | |
726 if (!file_exists($boarddir . '/Packages/' . $context['filename'])) | |
727 fatal_lang_error('package_no_file', false); | |
728 | |
729 // Load up the package FTP information? | |
730 create_chmod_control(array(), array('destination_url' => $scripturl . '?action=admin;area=packages;sa=' . $_REQUEST['sa'] . ';package=' . $_REQUEST['package'])); | |
731 | |
732 // Make sure temp directory exists and is empty! | |
733 if (file_exists($boarddir . '/Packages/temp')) | |
734 deltree($boarddir . '/Packages/temp', false); | |
735 else | |
736 mktree($boarddir . '/Packages/temp', 0777); | |
737 | |
738 // Let the unpacker do the work. | |
739 if (is_file($boarddir . '/Packages/' . $context['filename'])) | |
740 { | |
741 $context['extracted_files'] = read_tgz_file($boarddir . '/Packages/' . $context['filename'], $boarddir . '/Packages/temp'); | |
742 | |
743 if (!file_exists($boarddir . '/Packages/temp/package-info.xml')) | |
744 foreach ($context['extracted_files'] as $file) | |
745 if (basename($file['filename']) == 'package-info.xml') | |
746 { | |
747 $context['base_path'] = dirname($file['filename']) . '/'; | |
748 break; | |
749 } | |
750 | |
751 if (!isset($context['base_path'])) | |
752 $context['base_path'] = ''; | |
753 } | |
754 elseif (is_dir($boarddir . '/Packages/' . $context['filename'])) | |
755 { | |
756 copytree($boarddir . '/Packages/' . $context['filename'], $boarddir . '/Packages/temp'); | |
757 $context['extracted_files'] = listtree($boarddir . '/Packages/temp'); | |
758 $context['base_path'] = ''; | |
759 } | |
760 else | |
761 fatal_lang_error('no_access', false); | |
762 | |
763 // Are we installing this into any custom themes? | |
764 $custom_themes = array(1); | |
765 $known_themes = explode(',', $modSettings['knownThemes']); | |
766 if (!empty($_POST['custom_theme'])) | |
767 { | |
768 foreach ($_POST['custom_theme'] as $tid) | |
769 if (in_array($tid, $known_themes)) | |
770 $custom_themes[] = (int) $tid; | |
771 } | |
772 | |
773 // Now load up the paths of the themes that we need to know about. | |
774 $request = $smcFunc['db_query']('', ' | |
775 SELECT id_theme, variable, value | |
776 FROM {db_prefix}themes | |
777 WHERE id_theme IN ({array_int:custom_themes}) | |
778 AND variable IN ({string:name}, {string:theme_dir})', | |
779 array( | |
780 'custom_themes' => $custom_themes, | |
781 'name' => 'name', | |
782 'theme_dir' => 'theme_dir', | |
783 ) | |
784 ); | |
785 $theme_paths = array(); | |
786 $themes_installed = array(1); | |
787 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
788 $theme_paths[$row['id_theme']][$row['variable']] = $row['value']; | |
789 $smcFunc['db_free_result']($request); | |
790 | |
791 // Are there any theme copying that we want to take place? | |
792 $context['theme_copies'] = array( | |
793 'require-file' => array(), | |
794 'require-dir' => array(), | |
795 ); | |
796 if (!empty($_POST['theme_changes'])) | |
797 { | |
798 foreach ($_POST['theme_changes'] as $change) | |
799 { | |
800 if (empty($change)) | |
801 continue; | |
802 $theme_data = unserialize(base64_decode($change)); | |
803 if (empty($theme_data['type'])) | |
804 continue; | |
805 | |
806 $themes_installed[] = $theme_data['id']; | |
807 $context['theme_copies'][$theme_data['type']][$theme_data['orig']][] = $theme_data['future']; | |
808 } | |
809 } | |
810 | |
811 // Get the package info... | |
812 $packageInfo = getPackageInfo($context['filename']); | |
813 if (!is_array($packageInfo)) | |
814 fatal_lang_error($packageInfo); | |
815 | |
816 $packageInfo['filename'] = $context['filename']; | |
817 | |
818 // Set the type of extraction... | |
819 $context['extract_type'] = isset($packageInfo['type']) ? $packageInfo['type'] : 'modification'; | |
820 | |
821 // Create a backup file to roll back to! (but if they do this more than once, don't run it a zillion times.) | |
822 if (!empty($modSettings['package_make_backups']) && (!isset($_SESSION['last_backup_for']) || $_SESSION['last_backup_for'] != $context['filename'] . ($context['uninstalling'] ? '$$' : '$'))) | |
823 { | |
824 $_SESSION['last_backup_for'] = $context['filename'] . ($context['uninstalling'] ? '$$' : '$'); | |
825 // !!! Internationalize this? | |
826 package_create_backup(($context['uninstalling'] ? 'backup_' : 'before_') . strtok($context['filename'], '.')); | |
827 } | |
828 | |
829 // The mod isn't installed.... unless proven otherwise. | |
830 $context['is_installed'] = false; | |
831 | |
832 // Is it actually installed? | |
833 $request = $smcFunc['db_query']('', ' | |
834 SELECT version, themes_installed, db_changes | |
835 FROM {db_prefix}log_packages | |
836 WHERE package_id = {string:current_package} | |
837 AND install_state != {int:not_installed} | |
838 ORDER BY time_installed DESC | |
839 LIMIT 1', | |
840 array( | |
841 'not_installed' => 0, | |
842 'current_package' => $packageInfo['id'], | |
843 ) | |
844 ); | |
845 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
846 { | |
847 $old_themes = explode(',', $row['themes_installed']); | |
848 $old_version = $row['version']; | |
849 $db_changes = empty($row['db_changes']) ? array() : unserialize($row['db_changes']); | |
850 } | |
851 $smcFunc['db_free_result']($request); | |
852 | |
853 // Wait, it's not installed yet! | |
854 // !!! TODO: Replace with a better error message! | |
855 if (!isset($old_version) && $context['uninstalling']) | |
856 { | |
857 deltree($boarddir . '/Packages/temp'); | |
858 fatal_error('Hacker?', false); | |
859 } | |
860 // Uninstalling? | |
861 elseif ($context['uninstalling']) | |
862 { | |
863 $install_log = parsePackageInfo($packageInfo['xml'], false, 'uninstall'); | |
864 | |
865 // Gadzooks! There's no uninstaller at all!? | |
866 if (empty($install_log)) | |
867 fatal_lang_error('package_uninstall_cannot', false); | |
868 | |
869 // They can only uninstall from what it was originally installed into. | |
870 foreach ($theme_paths as $id => $data) | |
871 if ($id != 1 && !in_array($id, $old_themes)) | |
872 unset($theme_paths[$id]); | |
873 } | |
874 elseif (isset($old_version) && $old_version != $packageInfo['version']) | |
875 { | |
876 // Look for an upgrade... | |
877 $install_log = parsePackageInfo($packageInfo['xml'], false, 'upgrade', $old_version); | |
878 | |
879 // There was no upgrade.... | |
880 if (empty($install_log)) | |
881 $context['is_installed'] = true; | |
882 else | |
883 { | |
884 // Upgrade previous themes only! | |
885 foreach ($theme_paths as $id => $data) | |
886 if ($id != 1 && !in_array($id, $old_themes)) | |
887 unset($theme_paths[$id]); | |
888 } | |
889 } | |
890 elseif (isset($old_version) && $old_version == $packageInfo['version']) | |
891 $context['is_installed'] = true; | |
892 | |
893 if (!isset($old_version) || $context['is_installed']) | |
894 $install_log = parsePackageInfo($packageInfo['xml'], false, 'install'); | |
895 | |
896 $context['install_finished'] = false; | |
897 | |
898 // !!! TODO: Make a log of any errors that occurred and output them? | |
899 | |
900 if (!empty($install_log)) | |
901 { | |
902 $failed_steps = array(); | |
903 $failed_count = 0; | |
904 | |
905 foreach ($install_log as $action) | |
906 { | |
907 $failed_count++; | |
908 | |
909 if ($action['type'] == 'modification' && !empty($action['filename'])) | |
910 { | |
911 if ($action['boardmod']) | |
912 $mod_actions = parseBoardMod(file_get_contents($boarddir . '/Packages/temp/' . $context['base_path'] . $action['filename']), false, $action['reverse'], $theme_paths); | |
913 else | |
914 $mod_actions = parseModification(file_get_contents($boarddir . '/Packages/temp/' . $context['base_path'] . $action['filename']), false, $action['reverse'], $theme_paths); | |
915 | |
916 // Any errors worth noting? | |
917 foreach ($mod_actions as $key => $action) | |
918 { | |
919 if ($action['type'] == 'failure') | |
920 $failed_steps[] = array( | |
921 'file' => $action['filename'], | |
922 'large_step' => $failed_count, | |
923 'sub_step' => $key, | |
924 'theme' => 1, | |
925 ); | |
926 | |
927 // Gather the themes we installed into. | |
928 if (!empty($action['is_custom'])) | |
929 $themes_installed[] = $action['is_custom']; | |
930 } | |
931 } | |
932 elseif ($action['type'] == 'code' && !empty($action['filename'])) | |
933 { | |
934 // This is just here as reference for what is available. | |
935 global $txt, $boarddir, $sourcedir, $modSettings, $context, $settings, $forum_version, $smcFunc; | |
936 | |
937 // Now include the file and be done with it ;). | |
938 require($boarddir . '/Packages/temp/' . $context['base_path'] . $action['filename']); | |
939 } | |
940 // Only do the database changes on uninstall if requested. | |
941 elseif ($action['type'] == 'database' && !empty($action['filename']) && (!$context['uninstalling'] || !empty($_POST['do_db_changes']))) | |
942 { | |
943 // These can also be there for database changes. | |
944 global $txt, $boarddir, $sourcedir, $modSettings, $context, $settings, $forum_version, $smcFunc; | |
945 global $db_package_log; | |
946 | |
947 // We'll likely want the package specific database functionality! | |
948 db_extend('packages'); | |
949 | |
950 // Let the file work its magic ;) | |
951 require($boarddir . '/Packages/temp/' . $context['base_path'] . $action['filename']); | |
952 } | |
953 // Handle a redirect... | |
954 elseif ($action['type'] == 'redirect' && !empty($action['redirect_url'])) | |
955 { | |
956 $context['redirect_url'] = $action['redirect_url']; | |
957 $context['redirect_text'] = !empty($action['filename']) && file_exists($boarddir . '/Packages/temp/' . $context['base_path'] . $action['filename']) ? file_get_contents($boarddir . '/Packages/temp/' . $context['base_path'] . $action['filename']) : ($context['uninstalling'] ? $txt['package_uninstall_done'] : $txt['package_installed_done']); | |
958 $context['redirect_timeout'] = $action['redirect_timeout']; | |
959 | |
960 // Parse out a couple of common urls. | |
961 $urls = array( | |
962 '$boardurl' => $boardurl, | |
963 '$scripturl' => $scripturl, | |
964 '$session_var' => $context['session_var'], | |
965 '$session_id' => $context['session_id'], | |
966 ); | |
967 | |
968 $context['redirect_url'] = strtr($context['redirect_url'], $urls); | |
969 } | |
970 } | |
971 | |
972 package_flush_cache(); | |
973 | |
974 // First, ensure this change doesn't get removed by putting a stake in the ground (So to speak). | |
975 package_put_contents($boarddir . '/Packages/installed.list', time()); | |
976 | |
977 // See if this is already installed, and change it's state as required. | |
978 $request = $smcFunc['db_query']('', ' | |
979 SELECT package_id, install_state, db_changes | |
980 FROM {db_prefix}log_packages | |
981 WHERE install_state != {int:not_installed} | |
982 AND package_id = {string:current_package} | |
983 ' . ($context['install_id'] ? ' AND id_install = {int:install_id} ' : '') . ' | |
984 ORDER BY time_installed DESC | |
985 LIMIT 1', | |
986 array( | |
987 'not_installed' => 0, | |
988 'install_id' => $context['install_id'], | |
989 'current_package' => $packageInfo['id'], | |
990 ) | |
991 ); | |
992 $is_upgrade = false; | |
993 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
994 { | |
995 // Uninstalling? | |
996 if ($context['uninstalling']) | |
997 { | |
998 $smcFunc['db_query']('', ' | |
999 UPDATE {db_prefix}log_packages | |
1000 SET install_state = {int:not_installed}, member_removed = {string:member_name}, id_member_removed = {int:current_member}, | |
1001 time_removed = {int:current_time} | |
1002 WHERE package_id = {string:package_id}', | |
1003 array( | |
1004 'current_member' => $user_info['id'], | |
1005 'not_installed' => 0, | |
1006 'current_time' => time(), | |
1007 'package_id' => $row['package_id'], | |
1008 'member_name' => $user_info['name'], | |
1009 ) | |
1010 ); | |
1011 } | |
1012 // Otherwise must be an upgrade. | |
1013 else | |
1014 { | |
1015 $is_upgrade = true; | |
1016 $old_db_changes = empty($row['db_changes']) ? array() : unserialize($row['db_changes']); | |
1017 } | |
1018 } | |
1019 | |
1020 // Assuming we're not uninstalling, add the entry. | |
1021 if (!$context['uninstalling']) | |
1022 { | |
1023 // Any db changes from older version? | |
1024 if (!empty($old_db_changes)) | |
1025 $db_package_log = empty($db_package_log) ? $old_db_changes : array_merge($old_db_changes, $db_package_log); | |
1026 | |
1027 // If there are some database changes we might want to remove then filter them out. | |
1028 if (!empty($db_package_log)) | |
1029 { | |
1030 // We're really just checking for entries which are create table AND add columns (etc). | |
1031 $tables = array(); | |
1032 function sort_table_first($a, $b) | |
1033 { | |
1034 if ($a[0] == $b[0]) | |
1035 return 0; | |
1036 return $a[0] == 'remove_table' ? -1 : 1; | |
1037 } | |
1038 usort($db_package_log, 'sort_table_first'); | |
1039 foreach ($db_package_log as $k => $log) | |
1040 { | |
1041 if ($log[0] == 'remove_table') | |
1042 $tables[] = $log[1]; | |
1043 elseif (in_array($log[1], $tables)) | |
1044 unset($db_package_log[$k]); | |
1045 } | |
1046 $db_changes = serialize($db_package_log); | |
1047 } | |
1048 else | |
1049 $db_changes = ''; | |
1050 | |
1051 // What themes did we actually install? | |
1052 $themes_installed = array_unique($themes_installed); | |
1053 $themes_installed = implode(',', $themes_installed); | |
1054 | |
1055 // What failed steps? | |
1056 $failed_step_insert = serialize($failed_steps); | |
1057 | |
1058 $smcFunc['db_insert']('', | |
1059 '{db_prefix}log_packages', | |
1060 array( | |
1061 'filename' => 'string', 'name' => 'string', 'package_id' => 'string', 'version' => 'string', | |
1062 'id_member_installed' => 'int', 'member_installed' => 'string','time_installed' => 'int', | |
1063 'install_state' => 'int', 'failed_steps' => 'string', 'themes_installed' => 'string', | |
1064 'member_removed' => 'int', 'db_changes' => 'string', | |
1065 ), | |
1066 array( | |
1067 $packageInfo['filename'], $packageInfo['name'], $packageInfo['id'], $packageInfo['version'], | |
1068 $user_info['id'], $user_info['name'], time(), | |
1069 $is_upgrade ? 2 : 1, $failed_step_insert, $themes_installed, | |
1070 0, $db_changes, | |
1071 ), | |
1072 array('id_install') | |
1073 ); | |
1074 } | |
1075 $smcFunc['db_free_result']($request); | |
1076 | |
1077 $context['install_finished'] = true; | |
1078 } | |
1079 | |
1080 // If there's database changes - and they want them removed - let's do it last! | |
1081 if (!empty($db_changes) && !empty($_POST['do_db_changes'])) | |
1082 { | |
1083 // We're gonna be needing the package db functions! | |
1084 db_extend('packages'); | |
1085 | |
1086 foreach ($db_changes as $change) | |
1087 { | |
1088 if ($change[0] == 'remove_table' && isset($change[1])) | |
1089 $smcFunc['db_drop_table']($change[1]); | |
1090 elseif ($change[0] == 'remove_column' && isset($change[2])) | |
1091 $smcFunc['db_remove_column']($change[1], $change[2]); | |
1092 elseif ($change[0] == 'remove_index' && isset($change[2])) | |
1093 $smcFunc['db_remove_index']($change[1], $change[2]); | |
1094 } | |
1095 } | |
1096 | |
1097 // Clean house... get rid of the evidence ;). | |
1098 if (file_exists($boarddir . '/Packages/temp')) | |
1099 deltree($boarddir . '/Packages/temp'); | |
1100 | |
1101 // Log what we just did. | |
1102 logAction($context['uninstalling'] ? 'uninstall_package' : (!empty($is_upgrade) ? 'upgrade_package' : 'install_package'), array('package' => $smcFunc['htmlspecialchars']($packageInfo['name']), 'version' => $smcFunc['htmlspecialchars']($packageInfo['version'])), 'admin'); | |
1103 | |
1104 // Just in case, let's clear the whole cache to avoid anything going up the swanny. | |
1105 clean_cache(); | |
1106 | |
1107 // Restore file permissions? | |
1108 create_chmod_control(array(), array(), true); | |
1109 } | |
1110 | |
1111 // List the files in a package. | |
1112 function PackageList() | |
1113 { | |
1114 global $txt, $scripturl, $boarddir, $context, $sourcedir; | |
1115 | |
1116 require_once($sourcedir . '/Subs-Package.php'); | |
1117 | |
1118 // No package? Show him or her the door. | |
1119 if (!isset($_REQUEST['package']) || $_REQUEST['package'] == '') | |
1120 redirectexit('action=admin;area=packages'); | |
1121 | |
1122 $context['linktree'][] = array( | |
1123 'url' => $scripturl . '?action=admin;area=packages;sa=list;package=' . $_REQUEST['package'], | |
1124 'name' => $txt['list_file'] | |
1125 ); | |
1126 $context['page_title'] .= ' - ' . $txt['list_file']; | |
1127 $context['sub_template'] = 'list'; | |
1128 | |
1129 // The filename... | |
1130 $context['filename'] = $_REQUEST['package']; | |
1131 | |
1132 // Let the unpacker do the work. | |
1133 if (is_file($boarddir . '/Packages/' . $context['filename'])) | |
1134 $context['files'] = read_tgz_file($boarddir . '/Packages/' . $context['filename'], null); | |
1135 elseif (is_dir($boarddir . '/Packages/' . $context['filename'])) | |
1136 $context['files'] = listtree($boarddir . '/Packages/' . $context['filename']); | |
1137 } | |
1138 | |
1139 // List the files in a package. | |
1140 function ExamineFile() | |
1141 { | |
1142 global $txt, $scripturl, $boarddir, $context, $sourcedir; | |
1143 | |
1144 require_once($sourcedir . '/Subs-Package.php'); | |
1145 | |
1146 // No package? Show him or her the door. | |
1147 if (!isset($_REQUEST['package']) || $_REQUEST['package'] == '') | |
1148 redirectexit('action=admin;area=packages'); | |
1149 | |
1150 // No file? Show him or her the door. | |
1151 if (!isset($_REQUEST['file']) || $_REQUEST['file'] == '') | |
1152 redirectexit('action=admin;area=packages'); | |
1153 | |
1154 $_REQUEST['package'] = preg_replace('~[\.]+~', '.', strtr($_REQUEST['package'], array('/' => '_', '\\' => '_'))); | |
1155 $_REQUEST['file'] = preg_replace('~[\.]+~', '.', $_REQUEST['file']); | |
1156 | |
1157 if (isset($_REQUEST['raw'])) | |
1158 { | |
1159 if (is_file($boarddir . '/Packages/' . $_REQUEST['package'])) | |
1160 echo read_tgz_file($boarddir . '/Packages/' . $_REQUEST['package'], $_REQUEST['file'], true); | |
1161 elseif (is_dir($boarddir . '/Packages/' . $_REQUEST['package'])) | |
1162 echo file_get_contents($boarddir . '/Packages/' . $_REQUEST['package'] . '/' . $_REQUEST['file']); | |
1163 | |
1164 obExit(false); | |
1165 } | |
1166 | |
1167 $context['linktree'][count($context['linktree']) - 1] = array( | |
1168 'url' => $scripturl . '?action=admin;area=packages;sa=list;package=' . $_REQUEST['package'], | |
1169 'name' => $txt['package_examine_file'] | |
1170 ); | |
1171 $context['page_title'] .= ' - ' . $txt['package_examine_file']; | |
1172 $context['sub_template'] = 'examine'; | |
1173 | |
1174 // The filename... | |
1175 $context['package'] = $_REQUEST['package']; | |
1176 $context['filename'] = $_REQUEST['file']; | |
1177 | |
1178 // Let the unpacker do the work.... but make sure we handle images properly. | |
1179 if (in_array(strtolower(strrchr($_REQUEST['file'], '.')), array('.bmp', '.gif', '.jpeg', '.jpg', '.png'))) | |
1180 $context['filedata'] = '<img src="' . $scripturl . '?action=admin;area=packages;sa=examine;package=' . $_REQUEST['package'] . ';file=' . $_REQUEST['file'] . ';raw" alt="' . $_REQUEST['file'] . '" />'; | |
1181 else | |
1182 { | |
1183 if (is_file($boarddir . '/Packages/' . $_REQUEST['package'])) | |
1184 $context['filedata'] = htmlspecialchars(read_tgz_file($boarddir . '/Packages/' . $_REQUEST['package'], $_REQUEST['file'], true)); | |
1185 elseif (is_dir($boarddir . '/Packages/' . $_REQUEST['package'])) | |
1186 $context['filedata'] = htmlspecialchars(file_get_contents($boarddir . '/Packages/' . $_REQUEST['package'] . '/' . $_REQUEST['file'])); | |
1187 | |
1188 if (strtolower(strrchr($_REQUEST['file'], '.')) == '.php') | |
1189 $context['filedata'] = highlight_php_code($context['filedata']); | |
1190 } | |
1191 } | |
1192 | |
1193 // List the installed packages. | |
1194 function InstalledList() | |
1195 { | |
1196 global $txt, $scripturl, $context; | |
1197 | |
1198 $context['page_title'] .= ' - ' . $txt['installed_packages']; | |
1199 $context['sub_template'] = 'view_installed'; | |
1200 | |
1201 // Load the installed mods and send them to the template. | |
1202 $context['installed_mods'] = loadInstalledPackages(); | |
1203 } | |
1204 | |
1205 // Empty out the installed list. | |
1206 function FlushInstall() | |
1207 { | |
1208 global $boarddir, $sourcedir, $smcFunc; | |
1209 | |
1210 // Always check the session. | |
1211 checkSession('get'); | |
1212 | |
1213 include_once($sourcedir . '/Subs-Package.php'); | |
1214 | |
1215 // Record when we last did this. | |
1216 package_put_contents($boarddir . '/Packages/installed.list', time()); | |
1217 | |
1218 // Set everything as uninstalled. | |
1219 $smcFunc['db_query']('', ' | |
1220 UPDATE {db_prefix}log_packages | |
1221 SET install_state = {int:not_installed}', | |
1222 array( | |
1223 'not_installed' => 0, | |
1224 ) | |
1225 ); | |
1226 | |
1227 redirectexit('action=admin;area=packages;sa=installed'); | |
1228 } | |
1229 | |
1230 // Delete a package. | |
1231 function PackageRemove() | |
1232 { | |
1233 global $scripturl, $boarddir; | |
1234 | |
1235 // Check it. | |
1236 checkSession('get'); | |
1237 | |
1238 // Ack, don't allow deletion of arbitrary files here, could become a security hole somehow! | |
1239 if (!isset($_GET['package']) || $_GET['package'] == 'index.php' || $_GET['package'] == 'installed.list' || $_GET['package'] == 'backups') | |
1240 redirectexit('action=admin;area=packages;sa=browse'); | |
1241 $_GET['package'] = preg_replace('~[\.]+~', '.', strtr($_GET['package'], array('/' => '_', '\\' => '_'))); | |
1242 | |
1243 // Can't delete what's not there. | |
1244 if (file_exists($boarddir . '/Packages/' . $_GET['package']) && (substr($_GET['package'], -4) == '.zip' || substr($_GET['package'], -4) == '.tgz' || substr($_GET['package'], -7) == '.tar.gz' || is_dir($boarddir . '/Packages/' . $_GET['package'])) && $_GET['package'] != 'backups' && substr($_GET['package'], 0, 1) != '.') | |
1245 { | |
1246 create_chmod_control(array($boarddir . '/Packages/' . $_GET['package']), array('destination_url' => $scripturl . '?action=admin;area=packages;sa=remove;package=' . $_GET['package'], 'crash_on_error' => true)); | |
1247 | |
1248 if (is_dir($boarddir . '/Packages/' . $_GET['package'])) | |
1249 deltree($boarddir . '/Packages/' . $_GET['package']); | |
1250 else | |
1251 { | |
1252 @chmod($boarddir . '/Packages/' . $_GET['package'], 0777); | |
1253 unlink($boarddir . '/Packages/' . $_GET['package']); | |
1254 } | |
1255 } | |
1256 | |
1257 redirectexit('action=admin;area=packages;sa=browse'); | |
1258 } | |
1259 | |
1260 // Browse a list of installed packages. | |
1261 function PackageBrowse() | |
1262 { | |
1263 global $txt, $boarddir, $scripturl, $context, $forum_version; | |
1264 | |
1265 $context['page_title'] .= ' - ' . $txt['browse_packages']; | |
1266 $context['sub_template'] = 'browse'; | |
1267 | |
1268 $context['forum_version'] = $forum_version; | |
1269 | |
1270 $instmods = loadInstalledPackages(); | |
1271 | |
1272 $installed_mods = array(); | |
1273 // Look through the list of installed mods... | |
1274 foreach ($instmods as $installed_mod) | |
1275 $installed_mods[$installed_mod['package_id']] = array( | |
1276 'id' => $installed_mod['id'], | |
1277 'version' => $installed_mod['version'], | |
1278 ); | |
1279 | |
1280 $the_version = strtr($forum_version, array('SMF ' => '')); | |
1281 | |
1282 // Here we have a little code to help those who class themselves as something of gods, version emulation ;) | |
1283 if (isset($_GET['version_emulate'])) | |
1284 { | |
1285 if ($_GET['version_emulate'] === 0 && isset($_SESSION['version_emulate'])) | |
1286 unset($_SESSION['version_emulate']); | |
1287 elseif ($_GET['version_emulate'] !== 0) | |
1288 $_SESSION['version_emulate'] = strtr($_GET['version_emulate'], array('-' => ' ', '+' => ' ', 'SMF ' => '')); | |
1289 } | |
1290 if (!empty($_SESSION['version_emulate'])) | |
1291 { | |
1292 $context['forum_version'] = 'SMF ' . $_SESSION['version_emulate']; | |
1293 $the_version = $_SESSION['version_emulate']; | |
1294 } | |
1295 | |
1296 // Get a list of all the ids installed, so the latest packages won't include already installed ones. | |
1297 $context['installed_mods'] = array_keys($installed_mods); | |
1298 | |
1299 // Empty lists for now. | |
1300 $context['available_mods'] = array(); | |
1301 $context['available_avatars'] = array(); | |
1302 $context['available_languages'] = array(); | |
1303 $context['available_other'] = array(); | |
1304 $context['available_all'] = array(); | |
1305 | |
1306 // We need the packages directory to be writable for this. | |
1307 if (!@is_writable($boarddir . '/Packages')) | |
1308 create_chmod_control(array($boarddir . '/Packages'), array('destination_url' => $scripturl . '?action=admin;area=packages', 'crash_on_error' => true)); | |
1309 | |
1310 if ($dir = @opendir($boarddir . '/Packages')) | |
1311 { | |
1312 $dirs = array(); | |
1313 while ($package = readdir($dir)) | |
1314 { | |
1315 if ($package == '.' || $package == '..' || $package == 'temp' || (!(is_dir($boarddir . '/Packages/' . $package) && file_exists($boarddir . '/Packages/' . $package . '/package-info.xml')) && substr(strtolower($package), -7) != '.tar.gz' && substr(strtolower($package), -4) != '.tgz' && substr(strtolower($package), -4) != '.zip')) | |
1316 continue; | |
1317 | |
1318 // Skip directories or files that are named the same. | |
1319 if (is_dir($boarddir . '/Packages/' . $package)) | |
1320 { | |
1321 if (in_array($package, $dirs)) | |
1322 continue; | |
1323 $dirs[] = $package; | |
1324 } | |
1325 elseif (substr(strtolower($package), -7) == '.tar.gz') | |
1326 { | |
1327 if (in_array(substr($package, 0, -7), $dirs)) | |
1328 continue; | |
1329 $dirs[] = substr($package, 0, -7); | |
1330 } | |
1331 elseif (substr(strtolower($package), -4) == '.zip' || substr(strtolower($package), -4) == '.tgz') | |
1332 { | |
1333 if (in_array(substr($package, 0, -4), $dirs)) | |
1334 continue; | |
1335 $dirs[] = substr($package, 0, -4); | |
1336 } | |
1337 | |
1338 $packageInfo = getPackageInfo($package); | |
1339 if (!is_array($packageInfo)) | |
1340 continue; | |
1341 | |
1342 $packageInfo['installed_id'] = isset($installed_mods[$packageInfo['id']]) ? $installed_mods[$packageInfo['id']]['id'] : 0; | |
1343 | |
1344 $packageInfo['is_installed'] = isset($installed_mods[$packageInfo['id']]); | |
1345 $packageInfo['is_current'] = $packageInfo['is_installed'] && ($installed_mods[$packageInfo['id']]['version'] == $packageInfo['version']); | |
1346 $packageInfo['is_newer'] = $packageInfo['is_installed'] && ($installed_mods[$packageInfo['id']]['version'] > $packageInfo['version']); | |
1347 | |
1348 $packageInfo['can_install'] = false; | |
1349 $packageInfo['can_uninstall'] = false; | |
1350 $packageInfo['can_upgrade'] = false; | |
1351 | |
1352 // This package is currently NOT installed. Check if it can be. | |
1353 if (!$packageInfo['is_installed'] && $packageInfo['xml']->exists('install')) | |
1354 { | |
1355 // Check if there's an install for *THIS* version of SMF. | |
1356 $installs = $packageInfo['xml']->set('install'); | |
1357 foreach ($installs as $install) | |
1358 { | |
1359 if (!$install->exists('@for') || matchPackageVersion($the_version, $install->fetch('@for'))) | |
1360 { | |
1361 // Okay, this one is good to go. | |
1362 $packageInfo['can_install'] = true; | |
1363 break; | |
1364 } | |
1365 } | |
1366 } | |
1367 // An already installed, but old, package. Can we upgrade it? | |
1368 elseif ($packageInfo['is_installed'] && !$packageInfo['is_current'] && $packageInfo['xml']->exists('upgrade')) | |
1369 { | |
1370 $upgrades = $packageInfo['xml']->set('upgrade'); | |
1371 | |
1372 // First go through, and check against the current version of SMF. | |
1373 foreach ($upgrades as $upgrade) | |
1374 { | |
1375 // Even if it is for this SMF, is it for the installed version of the mod? | |
1376 if (!$upgrade->exists('@for') || matchPackageVersion($the_version, $upgrade->fetch('@for'))) | |
1377 if (!$upgrade->exists('@from') || matchPackageVersion($installed_mods[$packageInfo['id']]['version'], $upgrade->fetch('@from'))) | |
1378 { | |
1379 $packageInfo['can_upgrade'] = true; | |
1380 break; | |
1381 } | |
1382 } | |
1383 } | |
1384 // Note that it has to be the current version to be uninstallable. Shucks. | |
1385 elseif ($packageInfo['is_installed'] && $packageInfo['is_current'] && $packageInfo['xml']->exists('uninstall')) | |
1386 { | |
1387 $uninstalls = $packageInfo['xml']->set('uninstall'); | |
1388 | |
1389 // Can we find any uninstallation methods that work for this SMF version? | |
1390 foreach ($uninstalls as $uninstall) | |
1391 if (!$uninstall->exists('@for') || matchPackageVersion($the_version, $uninstall->fetch('@for'))) | |
1392 { | |
1393 $packageInfo['can_uninstall'] = true; | |
1394 break; | |
1395 } | |
1396 } | |
1397 | |
1398 // Store a complete list. | |
1399 $context['available_all'][] = $packageInfo; | |
1400 | |
1401 // Modification. | |
1402 if ($packageInfo['type'] == 'modification' || $packageInfo['type'] == 'mod') | |
1403 $context['available_mods'][] = $packageInfo; | |
1404 // Avatar package. | |
1405 elseif ($packageInfo['type'] == 'avatar') | |
1406 $context['available_avatars'][] = $packageInfo; | |
1407 // Language package. | |
1408 elseif ($packageInfo['type'] == 'language') | |
1409 $context['available_languages'][] = $packageInfo; | |
1410 // Other stuff. | |
1411 else | |
1412 $context['available_other'][] = $packageInfo; | |
1413 } | |
1414 closedir($dir); | |
1415 } | |
1416 } | |
1417 | |
1418 function PackageOptions() | |
1419 { | |
1420 global $txt, $scripturl, $context, $sourcedir, $modSettings, $smcFunc; | |
1421 | |
1422 if (isset($_POST['submit'])) | |
1423 { | |
1424 checkSession('post'); | |
1425 | |
1426 updateSettings(array( | |
1427 'package_server' => trim($smcFunc['htmlspecialchars']($_POST['pack_server'])), | |
1428 'package_port' => trim($smcFunc['htmlspecialchars']($_POST['pack_port'])), | |
1429 'package_username' => trim($smcFunc['htmlspecialchars']($_POST['pack_user'])), | |
1430 'package_make_backups' => !empty($_POST['package_make_backups']) | |
1431 )); | |
1432 | |
1433 redirectexit('action=admin;area=packages;sa=options'); | |
1434 } | |
1435 | |
1436 if (preg_match('~^/home/([^/]+?)/public_html~', $_SERVER['DOCUMENT_ROOT'], $match)) | |
1437 $default_username = $match[1]; | |
1438 else | |
1439 $default_username = ''; | |
1440 | |
1441 $context['page_title'] = $txt['package_settings']; | |
1442 $context['sub_template'] = 'install_options'; | |
1443 | |
1444 $context['package_ftp_server'] = isset($modSettings['package_server']) ? $modSettings['package_server'] : 'localhost'; | |
1445 $context['package_ftp_port'] = isset($modSettings['package_port']) ? $modSettings['package_port'] : '21'; | |
1446 $context['package_ftp_username'] = isset($modSettings['package_username']) ? $modSettings['package_username'] : $default_username; | |
1447 $context['package_make_backups'] = !empty($modSettings['package_make_backups']); | |
1448 } | |
1449 | |
1450 function ViewOperations() | |
1451 { | |
1452 global $context, $txt, $boarddir, $sourcedir, $smcFunc, $modSettings; | |
1453 | |
1454 // Can't be in here buddy. | |
1455 isAllowedTo('admin_forum'); | |
1456 | |
1457 // We need to know the operation key for the search and replace, mod file looking at, is it a board mod? | |
1458 if (!isset($_REQUEST['operation_key'], $_REQUEST['filename']) && !is_numeric($_REQUEST['operation_key'])) | |
1459 fatal_lang_error('operation_invalid', 'general'); | |
1460 | |
1461 // Load the required file. | |
1462 require_once($sourcedir . '/Subs-Package.php'); | |
1463 | |
1464 // Uninstalling the mod? | |
1465 $reverse = isset($_REQUEST['reverse']) ? true : false; | |
1466 | |
1467 // Get the base name. | |
1468 $context['filename'] = preg_replace('~[\.]+~', '.', $_REQUEST['package']); | |
1469 | |
1470 // We need to extract this again. | |
1471 if (is_file($boarddir . '/Packages/' . $context['filename'])) | |
1472 { | |
1473 $context['extracted_files'] = read_tgz_file($boarddir . '/Packages/' . $context['filename'], $boarddir . '/Packages/temp'); | |
1474 | |
1475 if ($context['extracted_files'] && !file_exists($boarddir . '/Packages/temp/package-info.xml')) | |
1476 foreach ($context['extracted_files'] as $file) | |
1477 if (basename($file['filename']) == 'package-info.xml') | |
1478 { | |
1479 $context['base_path'] = dirname($file['filename']) . '/'; | |
1480 break; | |
1481 } | |
1482 | |
1483 if (!isset($context['base_path'])) | |
1484 $context['base_path'] = ''; | |
1485 } | |
1486 elseif (is_dir($boarddir . '/Packages/' . $context['filename'])) | |
1487 { | |
1488 copytree($boarddir . '/Packages/' . $context['filename'], $boarddir . '/Packages/temp'); | |
1489 $context['extracted_files'] = listtree($boarddir . '/Packages/temp'); | |
1490 $context['base_path'] = ''; | |
1491 } | |
1492 | |
1493 // Load up any custom themes we may want to install into... | |
1494 $request = $smcFunc['db_query']('', ' | |
1495 SELECT id_theme, variable, value | |
1496 FROM {db_prefix}themes | |
1497 WHERE (id_theme = {int:default_theme} OR id_theme IN ({array_int:known_theme_list})) | |
1498 AND variable IN ({string:name}, {string:theme_dir})', | |
1499 array( | |
1500 'known_theme_list' => explode(',', $modSettings['knownThemes']), | |
1501 'default_theme' => 1, | |
1502 'name' => 'name', | |
1503 'theme_dir' => 'theme_dir', | |
1504 ) | |
1505 ); | |
1506 $theme_paths = array(); | |
1507 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
1508 $theme_paths[$row['id_theme']][$row['variable']] = $row['value']; | |
1509 $smcFunc['db_free_result']($request); | |
1510 | |
1511 // Boardmod? | |
1512 if (isset($_REQUEST['boardmod'])) | |
1513 $mod_actions = parseBoardMod(@file_get_contents($boarddir . '/Packages/temp/' . $context['base_path'] . $_REQUEST['filename']), true, $reverse, $theme_paths); | |
1514 else | |
1515 $mod_actions = parseModification(@file_get_contents($boarddir . '/Packages/temp/' . $context['base_path'] . $_REQUEST['filename']), true, $reverse, $theme_paths); | |
1516 | |
1517 // Ok lets get the content of the file. | |
1518 $context['operations'] = array( | |
1519 'search' => strtr(htmlspecialchars($mod_actions[$_REQUEST['operation_key']]['search_original']), array('[' => '[', ']' => ']')), | |
1520 'replace' => strtr(htmlspecialchars($mod_actions[$_REQUEST['operation_key']]['replace_original']), array('[' => '[', ']' => ']')), | |
1521 'position' => $mod_actions[$_REQUEST['operation_key']]['position'], | |
1522 ); | |
1523 | |
1524 // Let's do some formatting... | |
1525 $operation_text = $context['operations']['position'] == 'replace' ? 'operation_replace' : ($context['operations']['position'] == 'before' ? 'operation_after' : 'operation_before'); | |
1526 $context['operations']['search'] = parse_bbc('[code=' . $txt['operation_find'] . ']' . ($context['operations']['position'] == 'end' ? '?>' : $context['operations']['search']) . '[/code]'); | |
1527 $context['operations']['replace'] = parse_bbc('[code=' . $txt[$operation_text] . ']' . $context['operations']['replace'] . '[/code]'); | |
1528 | |
1529 // No layers | |
1530 $context['template_layers'] = array(); | |
1531 $context['sub_template'] = 'view_operations'; | |
1532 } | |
1533 | |
1534 // Allow the admin to reset permissions on files. | |
1535 function PackagePermissions() | |
1536 { | |
1537 global $context, $txt, $modSettings, $boarddir, $sourcedir, $cachedir, $smcFunc, $package_ftp; | |
1538 | |
1539 // Let's try and be good, yes? | |
1540 checkSession('get'); | |
1541 | |
1542 // If we're restoring permissions this is just a pass through really. | |
1543 if (isset($_GET['restore'])) | |
1544 { | |
1545 create_chmod_control(array(), array(), true); | |
1546 fatal_lang_error('no_access', false); | |
1547 } | |
1548 | |
1549 // This is a memory eat. | |
1550 @ini_set('memory_limit', '128M'); | |
1551 @set_time_limit(600); | |
1552 | |
1553 // Load up some FTP stuff. | |
1554 create_chmod_control(); | |
1555 | |
1556 if (empty($package_ftp) && !isset($_POST['skip_ftp'])) | |
1557 { | |
1558 loadClassFile('Class-Package.php'); | |
1559 $ftp = new ftp_connection(null); | |
1560 list ($username, $detect_path, $found_path) = $ftp->detect_path($boarddir); | |
1561 | |
1562 $context['package_ftp'] = array( | |
1563 'server' => isset($modSettings['package_server']) ? $modSettings['package_server'] : 'localhost', | |
1564 'port' => isset($modSettings['package_port']) ? $modSettings['package_port'] : '21', | |
1565 'username' => empty($username) ? (isset($modSettings['package_username']) ? $modSettings['package_username'] : '') : $username, | |
1566 'path' => $detect_path, | |
1567 'form_elements_only' => true, | |
1568 ); | |
1569 } | |
1570 else | |
1571 $context['ftp_connected'] = true; | |
1572 | |
1573 // Define the template. | |
1574 $context['page_title'] = $txt['package_file_perms']; | |
1575 $context['sub_template'] = 'file_permissions'; | |
1576 | |
1577 // Define what files we're interested in, as a tree. | |
1578 $context['file_tree'] = array( | |
1579 strtr($boarddir, array('\\' => '/')) => array( | |
1580 'type' => 'dir', | |
1581 'contents' => array( | |
1582 'agreement.txt' => array( | |
1583 'type' => 'file', | |
1584 'writable_on' => 'standard', | |
1585 ), | |
1586 'Settings.php' => array( | |
1587 'type' => 'file', | |
1588 'writable_on' => 'restrictive', | |
1589 ), | |
1590 'Settings_bak.php' => array( | |
1591 'type' => 'file', | |
1592 'writable_on' => 'restrictive', | |
1593 ), | |
1594 'attachments' => array( | |
1595 'type' => 'dir', | |
1596 'writable_on' => 'restrictive', | |
1597 ), | |
1598 'avatars' => array( | |
1599 'type' => 'dir', | |
1600 'writable_on' => 'standard', | |
1601 ), | |
1602 'cache' => array( | |
1603 'type' => 'dir', | |
1604 'writable_on' => 'restrictive', | |
1605 ), | |
1606 'custom_avatar_dir' => array( | |
1607 'type' => 'dir', | |
1608 'writable_on' => 'restrictive', | |
1609 ), | |
1610 'Smileys' => array( | |
1611 'type' => 'dir_recursive', | |
1612 'writable_on' => 'standard', | |
1613 ), | |
1614 'Sources' => array( | |
1615 'type' => 'dir', | |
1616 'list_contents' => true, | |
1617 'writable_on' => 'standard', | |
1618 ), | |
1619 'Themes' => array( | |
1620 'type' => 'dir_recursive', | |
1621 'writable_on' => 'standard', | |
1622 'contents' => array( | |
1623 'default' => array( | |
1624 'type' => 'dir_recursive', | |
1625 'list_contents' => true, | |
1626 'contents' => array( | |
1627 'languages' => array( | |
1628 'type' => 'dir', | |
1629 'list_contents' => true, | |
1630 ), | |
1631 ), | |
1632 ), | |
1633 ), | |
1634 ), | |
1635 'Packages' => array( | |
1636 'type' => 'dir', | |
1637 'writable_on' => 'standard', | |
1638 'contents' => array( | |
1639 'temp' => array( | |
1640 'type' => 'dir', | |
1641 ), | |
1642 'backup' => array( | |
1643 'type' => 'dir', | |
1644 ), | |
1645 'installed.list' => array( | |
1646 'type' => 'file', | |
1647 'writable_on' => 'standard', | |
1648 ), | |
1649 ), | |
1650 ), | |
1651 ), | |
1652 ), | |
1653 ); | |
1654 | |
1655 // Directories that can move. | |
1656 if (substr($sourcedir, 0, strlen($boarddir)) != $boarddir) | |
1657 { | |
1658 unset($context['file_tree'][strtr($boarddir, array('\\' => '/'))]['contents']['Sources']); | |
1659 $context['file_tree'][strtr($sourcedir, array('\\' => '/'))] = array( | |
1660 'type' => 'dir', | |
1661 'list_contents' => true, | |
1662 'writable_on' => 'standard', | |
1663 ); | |
1664 } | |
1665 | |
1666 // Moved the cache? | |
1667 if (substr($cachedir, 0, strlen($boarddir)) != $boarddir) | |
1668 { | |
1669 unset($context['file_tree'][strtr($boarddir, array('\\' => '/'))]['contents']['cache']); | |
1670 $context['file_tree'][strtr($cachedir, array('\\' => '/'))] = array( | |
1671 'type' => 'dir', | |
1672 'list_contents' => false, | |
1673 'writable_on' => 'restrictive', | |
1674 ); | |
1675 } | |
1676 | |
1677 // Are we using multiple attachment directories? | |
1678 if (!empty($modSettings['currentAttachmentUploadDir'])) | |
1679 { | |
1680 unset($context['file_tree'][strtr($boarddir, array('\\' => '/'))]['contents']['attachments']); | |
1681 | |
1682 if (!is_array($modSettings['attachmentUploadDir'])) | |
1683 $modSettings['attachmentUploadDir'] = unserialize($modSettings['attachmentUploadDir']); | |
1684 | |
1685 // !!! Should we suggest non-current directories be read only? | |
1686 foreach ($modSettings['attachmentUploadDir'] as $dir) | |
1687 $context['file_tree'][strtr($dir, array('\\' => '/'))] = array( | |
1688 'type' => 'dir', | |
1689 'writable_on' => 'restrictive', | |
1690 ); | |
1691 | |
1692 } | |
1693 elseif (substr($modSettings['attachmentUploadDir'], 0, strlen($boarddir)) != $boarddir) | |
1694 { | |
1695 unset($context['file_tree'][strtr($boarddir, array('\\' => '/'))]['contents']['attachments']); | |
1696 $context['file_tree'][strtr($modSettings['attachmentUploadDir'], array('\\' => '/'))] = array( | |
1697 'type' => 'dir', | |
1698 'writable_on' => 'restrictive', | |
1699 ); | |
1700 } | |
1701 | |
1702 if (substr($modSettings['smileys_dir'], 0, strlen($boarddir)) != $boarddir) | |
1703 { | |
1704 unset($context['file_tree'][strtr($boarddir, array('\\' => '/'))]['contents']['Smileys']); | |
1705 $context['file_tree'][strtr($modSettings['smileys_dir'], array('\\' => '/'))] = array( | |
1706 'type' => 'dir_recursive', | |
1707 'writable_on' => 'standard', | |
1708 ); | |
1709 } | |
1710 if (substr($modSettings['avatar_directory'], 0, strlen($boarddir)) != $boarddir) | |
1711 { | |
1712 unset($context['file_tree'][strtr($boarddir, array('\\' => '/'))]['contents']['avatars']); | |
1713 $context['file_tree'][strtr($modSettings['avatar_directory'], array('\\' => '/'))] = array( | |
1714 'type' => 'dir', | |
1715 'writable_on' => 'standard', | |
1716 ); | |
1717 } | |
1718 if (isset($modSettings['custom_avatar_dir']) && substr($modSettings['custom_avatar_dir'], 0, strlen($boarddir)) != $boarddir) | |
1719 { | |
1720 unset($context['file_tree'][strtr($boarddir, array('\\' => '/'))]['contents']['custom_avatar_dir']); | |
1721 $context['file_tree'][strtr($modSettings['custom_avatar_dir'], array('\\' => '/'))] = array( | |
1722 'type' => 'dir', | |
1723 'writable_on' => 'restrictive', | |
1724 ); | |
1725 } | |
1726 | |
1727 // Load up any custom themes. | |
1728 $request = $smcFunc['db_query']('', ' | |
1729 SELECT value | |
1730 FROM {db_prefix}themes | |
1731 WHERE id_theme > {int:default_theme_id} | |
1732 AND id_member = {int:guest_id} | |
1733 AND variable = {string:theme_dir} | |
1734 ORDER BY value ASC', | |
1735 array( | |
1736 'default_theme_id' => 1, | |
1737 'guest_id' => 0, | |
1738 'theme_dir' => 'theme_dir', | |
1739 ) | |
1740 ); | |
1741 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
1742 { | |
1743 if (substr(strtolower(strtr($row['value'], array('\\' => '/'))), 0, strlen($boarddir) + 7) == strtolower(strtr($boarddir, array('\\' => '/')) . '/Themes')) | |
1744 $context['file_tree'][strtr($boarddir, array('\\' => '/'))]['contents']['Themes']['contents'][substr($row['value'], strlen($boarddir) + 8)] = array( | |
1745 'type' => 'dir_recursive', | |
1746 'list_contents' => true, | |
1747 'contents' => array( | |
1748 'languages' => array( | |
1749 'type' => 'dir', | |
1750 'list_contents' => true, | |
1751 ), | |
1752 ), | |
1753 ); | |
1754 else | |
1755 { | |
1756 $context['file_tree'][strtr($row['value'], array('\\' => '/'))] = array( | |
1757 'type' => 'dir_recursive', | |
1758 'list_contents' => true, | |
1759 'contents' => array( | |
1760 'languages' => array( | |
1761 'type' => 'dir', | |
1762 'list_contents' => true, | |
1763 ), | |
1764 ), | |
1765 ); | |
1766 } | |
1767 } | |
1768 $smcFunc['db_free_result']($request); | |
1769 | |
1770 // If we're submitting then let's move on to another function to keep things cleaner.. | |
1771 if (isset($_POST['action_changes'])) | |
1772 return PackagePermissionsAction(); | |
1773 | |
1774 $context['look_for'] = array(); | |
1775 // Are we looking for a particular tree - normally an expansion? | |
1776 if (!empty($_REQUEST['find'])) | |
1777 $context['look_for'][] = base64_decode($_REQUEST['find']); | |
1778 // Only that tree? | |
1779 $context['only_find'] = isset($_GET['xml']) && !empty($_REQUEST['onlyfind']) ? $_REQUEST['onlyfind'] : ''; | |
1780 if ($context['only_find']) | |
1781 $context['look_for'][] = $context['only_find']; | |
1782 | |
1783 // Have we got a load of back-catalogue trees to expand from a submit etc? | |
1784 if (!empty($_GET['back_look'])) | |
1785 { | |
1786 $potententialTrees = unserialize(base64_decode($_GET['back_look'])); | |
1787 foreach ($potententialTrees as $tree) | |
1788 $context['look_for'][] = $tree; | |
1789 } | |
1790 // ... maybe posted? | |
1791 if (!empty($_POST['back_look'])) | |
1792 $context['only_find'] = array_merge($context['only_find'], $_POST['back_look']); | |
1793 | |
1794 $context['back_look_data'] = base64_encode(serialize(array_slice($context['look_for'], 0, 15))); | |
1795 | |
1796 // Are we finding more files than first thought? | |
1797 $context['file_offset'] = !empty($_REQUEST['fileoffset']) ? (int) $_REQUEST['fileoffset'] : 0; | |
1798 // Don't list more than this many files in a directory. | |
1799 $context['file_limit'] = 150; | |
1800 | |
1801 // How many levels shall we show? | |
1802 $context['default_level'] = empty($context['only_find']) ? 2 : 25; | |
1803 | |
1804 // This will be used if we end up catching XML data. | |
1805 $context['xml_data'] = array( | |
1806 'roots' => array( | |
1807 'identifier' => 'root', | |
1808 'children' => array( | |
1809 array( | |
1810 'value' => preg_replace('~[^A-Za-z0-9_\-=:]~', ':-:', $context['only_find']), | |
1811 ), | |
1812 ), | |
1813 ), | |
1814 'folders' => array( | |
1815 'identifier' => 'folder', | |
1816 'children' => array(), | |
1817 ), | |
1818 ); | |
1819 | |
1820 foreach ($context['file_tree'] as $path => $data) | |
1821 { | |
1822 // Run this directory. | |
1823 if (file_exists($path) && (empty($context['only_find']) || substr($context['only_find'], 0, strlen($path)) == $path)) | |
1824 { | |
1825 // Get the first level down only. | |
1826 fetchPerms__recursive($path, $context['file_tree'][$path], 1); | |
1827 $context['file_tree'][$path]['perms'] = array( | |
1828 'chmod' => @is_writable($path), | |
1829 'perms' => @fileperms($path), | |
1830 ); | |
1831 } | |
1832 else | |
1833 unset($context['file_tree'][$path]); | |
1834 } | |
1835 | |
1836 // Is this actually xml? | |
1837 if (isset($_GET['xml'])) | |
1838 { | |
1839 loadTemplate('Xml'); | |
1840 $context['sub_template'] = 'generic_xml'; | |
1841 $context['template_layers'] = array(); | |
1842 } | |
1843 } | |
1844 | |
1845 function fetchPerms__recursive($path, &$data, $level) | |
1846 { | |
1847 global $context; | |
1848 | |
1849 $isLikelyPath = false; | |
1850 foreach ($context['look_for'] as $possiblePath) | |
1851 if (substr($possiblePath, 0, strlen($path)) == $path) | |
1852 $isLikelyPath = true; | |
1853 | |
1854 // Is this where we stop? | |
1855 if (isset($_GET['xml']) && !empty($context['look_for']) && !$isLikelyPath) | |
1856 return; | |
1857 elseif ($level > $context['default_level'] && !$isLikelyPath) | |
1858 return; | |
1859 | |
1860 // Are we actually interested in saving this data? | |
1861 $save_data = empty($context['only_find']) || $context['only_find'] == $path; | |
1862 | |
1863 //!!! Shouldn't happen - but better error message? | |
1864 if (!is_dir($path)) | |
1865 fatal_lang_error('no_access', false); | |
1866 | |
1867 // This is where we put stuff we've found for sorting. | |
1868 $foundData = array( | |
1869 'files' => array(), | |
1870 'folders' => array(), | |
1871 ); | |
1872 | |
1873 $dh = opendir($path); | |
1874 while ($entry = readdir($dh)) | |
1875 { | |
1876 // Some kind of file? | |
1877 if (!is_dir($path . '/' . $entry)) | |
1878 { | |
1879 // Are we listing PHP files in this directory? | |
1880 if ($save_data && !empty($data['list_contents']) && substr($entry, -4) == '.php') | |
1881 $foundData['files'][$entry] = true; | |
1882 // A file we were looking for. | |
1883 elseif ($save_data && isset($data['contents'][$entry])) | |
1884 $foundData['files'][$entry] = true; | |
1885 } | |
1886 // It's a directory - we're interested one way or another, probably... | |
1887 elseif ($entry != '.' && $entry != '..') | |
1888 { | |
1889 // Going further? | |
1890 if ((!empty($data['type']) && $data['type'] == 'dir_recursive') || (isset($data['contents'][$entry]) && (!empty($data['contents'][$entry]['list_contents']) || (!empty($data['contents'][$entry]['type']) && $data['contents'][$entry]['type'] == 'dir_recursive')))) | |
1891 { | |
1892 if (!isset($data['contents'][$entry])) | |
1893 $foundData['folders'][$entry] = 'dir_recursive'; | |
1894 else | |
1895 $foundData['folders'][$entry] = true; | |
1896 | |
1897 // If this wasn't expected inherit the recusiveness... | |
1898 if (!isset($data['contents'][$entry])) | |
1899 // We need to do this as we will be going all recursive. | |
1900 $data['contents'][$entry] = array( | |
1901 'type' => 'dir_recursive', | |
1902 ); | |
1903 | |
1904 // Actually do the recursive stuff... | |
1905 fetchPerms__recursive($path . '/' . $entry, $data['contents'][$entry], $level + 1); | |
1906 } | |
1907 // Maybe it is a folder we are not descending into. | |
1908 elseif (isset($data['contents'][$entry])) | |
1909 $foundData['folders'][$entry] = true; | |
1910 // Otherwise we stop here. | |
1911 } | |
1912 } | |
1913 closedir($dh); | |
1914 | |
1915 // Nothing to see here? | |
1916 if (!$save_data) | |
1917 return; | |
1918 | |
1919 // Now actually add the data, starting with the folders. | |
1920 ksort($foundData['folders']); | |
1921 foreach ($foundData['folders'] as $folder => $type) | |
1922 { | |
1923 $additional_data = array( | |
1924 'perms' => array( | |
1925 'chmod' => @is_writable($path . '/' . $folder), | |
1926 'perms' => @fileperms($path . '/' . $folder), | |
1927 ), | |
1928 ); | |
1929 if ($type !== true) | |
1930 $additional_data['type'] = $type; | |
1931 | |
1932 // If there's an offset ignore any folders in XML mode. | |
1933 if (isset($_GET['xml']) && $context['file_offset'] == 0) | |
1934 { | |
1935 $context['xml_data']['folders']['children'][] = array( | |
1936 'attributes' => array( | |
1937 'writable' => $additional_data['perms']['chmod'] ? 1 : 0, | |
1938 'permissions' => substr(sprintf('%o', $additional_data['perms']['perms']), -4), | |
1939 'folder' => 1, | |
1940 'path' => $context['only_find'], | |
1941 'level' => $level, | |
1942 'more' => 0, | |
1943 'offset' => $context['file_offset'], | |
1944 'my_ident' => preg_replace('~[^A-Za-z0-9_\-=:]~', ':-:', $context['only_find'] . '/' . $folder), | |
1945 'ident' => preg_replace('~[^A-Za-z0-9_\-=:]~', ':-:', $context['only_find']), | |
1946 ), | |
1947 'value' => $folder, | |
1948 ); | |
1949 } | |
1950 elseif (!isset($_GET['xml'])) | |
1951 { | |
1952 if (isset($data['contents'][$folder])) | |
1953 $data['contents'][$folder] = array_merge($data['contents'][$folder], $additional_data); | |
1954 else | |
1955 $data['contents'][$folder] = $additional_data; | |
1956 } | |
1957 } | |
1958 | |
1959 // Now we want to do a similar thing with files. | |
1960 ksort($foundData['files']); | |
1961 $counter = -1; | |
1962 foreach ($foundData['files'] as $file => $dummy) | |
1963 { | |
1964 $counter++; | |
1965 | |
1966 // Have we reached our offset? | |
1967 if ($context['file_offset'] > $counter) | |
1968 continue; | |
1969 // Gone too far? | |
1970 if ($counter > ($context['file_offset'] + $context['file_limit'])) | |
1971 continue; | |
1972 | |
1973 $additional_data = array( | |
1974 'perms' => array( | |
1975 'chmod' => @is_writable($path . '/' . $file), | |
1976 'perms' => @fileperms($path . '/' . $file), | |
1977 ), | |
1978 ); | |
1979 | |
1980 // XML? | |
1981 if (isset($_GET['xml'])) | |
1982 { | |
1983 $context['xml_data']['folders']['children'][] = array( | |
1984 'attributes' => array( | |
1985 'writable' => $additional_data['perms']['chmod'] ? 1 : 0, | |
1986 'permissions' => substr(sprintf('%o', $additional_data['perms']['perms']), -4), | |
1987 'folder' => 0, | |
1988 'path' => $context['only_find'], | |
1989 'level' => $level, | |
1990 'more' => $counter == ($context['file_offset'] + $context['file_limit']) ? 1 : 0, | |
1991 'offset' => $context['file_offset'], | |
1992 'my_ident' => preg_replace('~[^A-Za-z0-9_\-=:]~', ':-:', $context['only_find'] . '/' . $file), | |
1993 'ident' => preg_replace('~[^A-Za-z0-9_\-=:]~', ':-:', $context['only_find']), | |
1994 ), | |
1995 'value' => $file, | |
1996 ); | |
1997 } | |
1998 elseif ($counter != ($context['file_offset'] + $context['file_limit'])) | |
1999 { | |
2000 if (isset($data['contents'][$file])) | |
2001 $data['contents'][$file] = array_merge($data['contents'][$file], $additional_data); | |
2002 else | |
2003 $data['contents'][$file] = $additional_data; | |
2004 } | |
2005 } | |
2006 } | |
2007 | |
2008 // Actually action the permission changes they want. | |
2009 function PackagePermissionsAction() | |
2010 { | |
2011 global $context, $txt, $time_start, $package_ftp; | |
2012 | |
2013 umask(0); | |
2014 | |
2015 $timeout_limit = 5; | |
2016 | |
2017 $context['method'] = $_POST['method'] == 'individual' ? 'individual' : 'predefined'; | |
2018 $context['sub_template'] = 'action_permissions'; | |
2019 $context['page_title'] = $txt['package_file_perms_applying']; | |
2020 $context['back_look_data'] = isset($_POST['back_look']) ? $_POST['back_look'] : array(); | |
2021 | |
2022 // Skipping use of FTP? | |
2023 if (empty($package_ftp)) | |
2024 $context['skip_ftp'] = true; | |
2025 | |
2026 // We'll start off in a good place, security. Make sure that if we're dealing with individual files that they seem in the right place. | |
2027 if ($context['method'] == 'individual') | |
2028 { | |
2029 // Only these path roots are legal. | |
2030 $legal_roots = array_keys($context['file_tree']); | |
2031 $context['custom_value'] = (int) $_POST['custom_value']; | |
2032 | |
2033 // Continuing? | |
2034 if (isset($_POST['toProcess'])) | |
2035 $_POST['permStatus'] = unserialize(base64_decode($_POST['toProcess'])); | |
2036 | |
2037 if (isset($_POST['permStatus'])) | |
2038 { | |
2039 $context['to_process'] = array(); | |
2040 $validate_custom = false; | |
2041 foreach ($_POST['permStatus'] as $path => $status) | |
2042 { | |
2043 // Nothing to see here? | |
2044 if ($status == 'no_change') | |
2045 continue; | |
2046 $legal = false; | |
2047 foreach ($legal_roots as $root) | |
2048 if (substr($path, 0, strlen($root)) == $root) | |
2049 $legal = true; | |
2050 | |
2051 if (!$legal) | |
2052 continue; | |
2053 | |
2054 // Check it exists. | |
2055 if (!file_exists($path)) | |
2056 continue; | |
2057 | |
2058 if ($status == 'custom') | |
2059 $validate_custom = true; | |
2060 | |
2061 // Now add it. | |
2062 $context['to_process'][$path] = $status; | |
2063 } | |
2064 $context['total_items'] = isset($_POST['totalItems']) ? (int) $_POST['totalItems'] : count($context['to_process']); | |
2065 | |
2066 // Make sure the chmod status is valid? | |
2067 if ($validate_custom) | |
2068 { | |
2069 if (preg_match('~^[4567][4567][4567]$~', $context['custom_value']) == false) | |
2070 fatal_error($txt['chmod_value_invalid']); | |
2071 } | |
2072 | |
2073 // Nothing to do? | |
2074 if (empty($context['to_process'])) | |
2075 redirectexit('action=admin;area=packages;sa=perms' . (!empty($context['back_look_data']) ? ';back_look=' . base64_encode(serialize($context['back_look_data'])) : '') . ';' . $context['session_var'] . '=' . $context['session_id']); | |
2076 } | |
2077 // Should never get here, | |
2078 else | |
2079 fatal_lang_error('no_access', false); | |
2080 | |
2081 // Setup the custom value. | |
2082 $custom_value = octdec('0' . $context['custom_value']); | |
2083 | |
2084 // Start processing items. | |
2085 foreach ($context['to_process'] as $path => $status) | |
2086 { | |
2087 if (in_array($status, array('execute', 'writable', 'read'))) | |
2088 package_chmod($path, $status); | |
2089 elseif ($status == 'custom' && !empty($custom_value)) | |
2090 { | |
2091 // Use FTP if we have it. | |
2092 if (!empty($package_ftp) && !empty($_SESSION['pack_ftp'])) | |
2093 { | |
2094 $ftp_file = strtr($path, array($_SESSION['pack_ftp']['root'] => '')); | |
2095 $package_ftp->chmod($ftp_file, $custom_value); | |
2096 } | |
2097 else | |
2098 @chmod($path, $custom_value); | |
2099 } | |
2100 | |
2101 // This fish is fried... | |
2102 unset($context['to_process'][$path]); | |
2103 | |
2104 // See if we're out of time? | |
2105 if (time() - array_sum(explode(' ', $time_start)) > $timeout_limit) | |
2106 return false; | |
2107 } | |
2108 } | |
2109 // If predefined this is a little different. | |
2110 else | |
2111 { | |
2112 $context['predefined_type'] = isset($_POST['predefined']) ? $_POST['predefined'] : 'restricted'; | |
2113 | |
2114 $context['total_items'] = isset($_POST['totalItems']) ? (int) $_POST['totalItems'] : 0; | |
2115 $context['directory_list'] = isset($_POST['dirList']) ? unserialize(base64_decode($_POST['dirList'])) : array(); | |
2116 | |
2117 $context['file_offset'] = isset($_POST['fileOffset']) ? (int) $_POST['fileOffset'] : 0; | |
2118 | |
2119 // Haven't counted the items yet? | |
2120 if (empty($context['total_items'])) | |
2121 { | |
2122 function count_directories__recursive($dir) | |
2123 { | |
2124 global $context; | |
2125 | |
2126 $count = 0; | |
2127 $dh = @opendir($dir); | |
2128 while ($entry = readdir($dh)) | |
2129 { | |
2130 if ($entry != '.' && $entry != '..' && is_dir($dir . '/' . $entry)) | |
2131 { | |
2132 $context['directory_list'][$dir . '/' . $entry] = 1; | |
2133 $count++; | |
2134 $count += count_directories__recursive($dir . '/' . $entry); | |
2135 } | |
2136 } | |
2137 closedir($dh); | |
2138 | |
2139 return $count; | |
2140 } | |
2141 | |
2142 foreach ($context['file_tree'] as $path => $data) | |
2143 { | |
2144 if (is_dir($path)) | |
2145 { | |
2146 $context['directory_list'][$path] = 1; | |
2147 $context['total_items'] += count_directories__recursive($path); | |
2148 $context['total_items']++; | |
2149 } | |
2150 } | |
2151 } | |
2152 | |
2153 // Have we built up our list of special files? | |
2154 if (!isset($_POST['specialFiles']) && $context['predefined_type'] != 'free') | |
2155 { | |
2156 $context['special_files'] = array(); | |
2157 function build_special_files__recursive($path, &$data) | |
2158 { | |
2159 global $context; | |
2160 | |
2161 if (!empty($data['writable_on'])) | |
2162 if ($context['predefined_type'] == 'standard' || $data['writable_on'] == 'restrictive') | |
2163 $context['special_files'][$path] = 1; | |
2164 | |
2165 if (!empty($data['contents'])) | |
2166 foreach ($data['contents'] as $name => $contents) | |
2167 build_special_files__recursive($path . '/' . $name, $contents); | |
2168 } | |
2169 | |
2170 foreach ($context['file_tree'] as $path => $data) | |
2171 build_special_files__recursive($path, $data); | |
2172 } | |
2173 // Free doesn't need special files. | |
2174 elseif ($context['predefined_type'] == 'free') | |
2175 $context['special_files'] = array(); | |
2176 else | |
2177 $context['special_files'] = unserialize(base64_decode($_POST['specialFiles'])); | |
2178 | |
2179 // Now we definitely know where we are, we need to go through again doing the chmod! | |
2180 foreach ($context['directory_list'] as $path => $dummy) | |
2181 { | |
2182 // Do the contents of the directory first. | |
2183 $dh = @opendir($path); | |
2184 $file_count = 0; | |
2185 $dont_chmod = false; | |
2186 while ($entry = readdir($dh)) | |
2187 { | |
2188 $file_count++; | |
2189 // Actually process this file? | |
2190 if (!$dont_chmod && !is_dir($path . '/' . $entry) && (empty($context['file_offset']) || $context['file_offset'] < $file_count)) | |
2191 { | |
2192 $status = $context['predefined_type'] == 'free' || isset($context['special_files'][$path . '/' . $entry]) ? 'writable' : 'execute'; | |
2193 package_chmod($path . '/' . $entry, $status); | |
2194 } | |
2195 | |
2196 // See if we're out of time? | |
2197 if (!$dont_chmod && time() - array_sum(explode(' ', $time_start)) > $timeout_limit) | |
2198 { | |
2199 $dont_chmod = true; | |
2200 // Don't do this again. | |
2201 $context['file_offset'] = $file_count; | |
2202 } | |
2203 } | |
2204 closedir($dh); | |
2205 | |
2206 // If this is set it means we timed out half way through. | |
2207 if ($dont_chmod) | |
2208 { | |
2209 $context['total_files'] = $file_count; | |
2210 return false; | |
2211 } | |
2212 | |
2213 // Do the actual directory. | |
2214 $status = $context['predefined_type'] == 'free' || isset($context['special_files'][$path]) ? 'writable' : 'execute'; | |
2215 package_chmod($path, $status); | |
2216 | |
2217 // We've finished the directory so no file offset, and no record. | |
2218 $context['file_offset'] = 0; | |
2219 unset($context['directory_list'][$path]); | |
2220 | |
2221 // See if we're out of time? | |
2222 if (time() - array_sum(explode(' ', $time_start)) > $timeout_limit) | |
2223 return false; | |
2224 } | |
2225 } | |
2226 | |
2227 // If we're here we are done! | |
2228 redirectexit('action=admin;area=packages;sa=perms' . (!empty($context['back_look_data']) ? ';back_look=' . base64_encode(serialize($context['back_look_data'])) : '') . ';' . $context['session_var'] . '=' . $context['session_id']); | |
2229 } | |
2230 | |
2231 // Test an FTP connection. | |
2232 function PackageFTPTest() | |
2233 { | |
2234 global $context, $txt, $package_ftp; | |
2235 | |
2236 checkSession('get'); | |
2237 | |
2238 // Try to make the FTP connection. | |
2239 create_chmod_control(array(), array('force_find_error' => true)); | |
2240 | |
2241 // Deal with the template stuff. | |
2242 loadTemplate('Xml'); | |
2243 $context['sub_template'] = 'generic_xml'; | |
2244 $context['template_layers'] = array(); | |
2245 | |
2246 // Define the return data, this is simple. | |
2247 $context['xml_data'] = array( | |
2248 'results' => array( | |
2249 'identifier' => 'result', | |
2250 'children' => array( | |
2251 array( | |
2252 'attributes' => array( | |
2253 'success' => !empty($package_ftp) ? 1 : 0, | |
2254 ), | |
2255 'value' => !empty($package_ftp) ? $txt['package_ftp_test_success'] : (isset($context['package_ftp'], $context['package_ftp']['error']) ? $context['package_ftp']['error'] : $txt['package_ftp_test_failed']), | |
2256 ), | |
2257 ), | |
2258 ), | |
2259 ); | |
2260 } | |
2261 | |
2262 ?> |