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