These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /** |
||
4 | * This, as you have probably guessed, is the crux on which SMF functions. |
||
5 | * Everything should start here, so all the setup and security is done |
||
6 | * properly. The most interesting part of this file is the action array in |
||
7 | * the smf_main() function. It is formatted as so: |
||
8 | * 'action-in-url' => array('Source-File.php', 'FunctionToCall'), |
||
9 | * |
||
10 | * Then, you can access the FunctionToCall() function from Source-File.php |
||
11 | * with the URL index.php?action=action-in-url. Relatively simple, no? |
||
12 | * |
||
13 | * Simple Machines Forum (SMF) |
||
14 | * |
||
15 | * @package SMF |
||
16 | * @author Simple Machines http://www.simplemachines.org |
||
17 | * @copyright 2018 Simple Machines and individual contributors |
||
18 | * @license http://www.simplemachines.org/about/smf/license.php BSD |
||
19 | * |
||
20 | * @version 2.1 Beta 4 |
||
21 | */ |
||
22 | |||
23 | $software_year = '2018'; |
||
24 | $forum_version = 'SMF 2.1 Beta 4'; |
||
25 | |||
26 | // Get everything started up... |
||
27 | define('SMF', 1); |
||
28 | error_reporting(E_ALL); |
||
29 | $time_start = microtime(true); |
||
30 | |||
31 | // This makes it so headers can be sent! |
||
32 | ob_start(); |
||
33 | |||
34 | // Do some cleaning, just in case. |
||
35 | View Code Duplication | foreach (array('db_character_set', 'cachedir') as $variable) |
|
36 | if (isset($GLOBALS[$variable])) |
||
37 | unset($GLOBALS[$variable], $GLOBALS[$variable]); |
||
38 | |||
39 | // Load the settings... |
||
40 | require_once(dirname(__FILE__) . '/Settings.php'); |
||
41 | |||
42 | // Make absolutely sure the cache directory is defined. |
||
43 | View Code Duplication | if ((empty($cachedir) || !file_exists($cachedir)) && file_exists($boarddir . '/cache')) |
|
44 | $cachedir = $boarddir . '/cache'; |
||
45 | |||
46 | // Without those we can't go anywhere |
||
47 | require_once($sourcedir . '/QueryString.php'); |
||
48 | require_once($sourcedir . '/Subs.php'); |
||
49 | require_once($sourcedir . '/Subs-Auth.php'); |
||
50 | require_once($sourcedir . '/Errors.php'); |
||
51 | require_once($sourcedir . '/Load.php'); |
||
52 | |||
53 | // If $maintenance is set specifically to 2, then we're upgrading or something. |
||
54 | if (!empty($maintenance) && $maintenance == 2) |
||
55 | display_maintenance_message(); |
||
56 | |||
57 | // Create a variable to store some SMF specific functions in. |
||
58 | $smcFunc = array(); |
||
59 | |||
60 | // Initiate the database connection and define some database functions to use. |
||
61 | loadDatabase(); |
||
62 | |||
63 | // Load the settings from the settings table, and perform operations like optimizing. |
||
64 | $context = array(); |
||
65 | reloadSettings(); |
||
66 | // Clean the request variables, add slashes, etc. |
||
67 | cleanRequest(); |
||
68 | |||
69 | // Seed the random generator. |
||
70 | if (empty($modSettings['rand_seed']) || mt_rand(1, 250) == 69) |
||
71 | smf_seed_generator(); |
||
72 | |||
73 | // Before we get carried away, are we doing a scheduled task? If so save CPU cycles by jumping out! |
||
74 | if (isset($_GET['scheduled'])) |
||
75 | { |
||
76 | require_once($sourcedir . '/ScheduledTasks.php'); |
||
77 | AutoTask(); |
||
78 | } |
||
79 | |||
80 | // And important includes. |
||
81 | require_once($sourcedir . '/Session.php'); |
||
82 | require_once($sourcedir . '/Errors.php'); |
||
83 | require_once($sourcedir . '/Logging.php'); |
||
84 | require_once($sourcedir . '/Security.php'); |
||
85 | require_once($sourcedir . '/Class-BrowserDetect.php'); |
||
86 | |||
87 | // Check if compressed output is enabled, supported, and not already being done. |
||
88 | if (!empty($modSettings['enableCompressedOutput']) && !headers_sent()) |
||
89 | { |
||
90 | // If zlib is being used, turn off output compression. |
||
91 | View Code Duplication | if (ini_get('zlib.output_compression') >= 1 || ini_get('output_handler') == 'ob_gzhandler') |
|
92 | $modSettings['enableCompressedOutput'] = '0'; |
||
93 | else |
||
94 | { |
||
95 | ob_end_clean(); |
||
96 | ob_start('ob_gzhandler'); |
||
97 | } |
||
98 | } |
||
99 | |||
100 | /** |
||
101 | * An autoloader for certain classes. |
||
102 | * |
||
103 | * @param string $class The fully-qualified class name. |
||
104 | */ |
||
105 | spl_autoload_register(function ($class) use ($sourcedir) |
||
106 | { |
||
107 | $classMap = array( |
||
108 | 'ReCaptcha\\' => 'ReCaptcha/', |
||
109 | 'MatthiasMullie\\Minify\\' => 'minify/src/', |
||
110 | 'MatthiasMullie\\PathConverter\\' => 'minify/path-converter/src/', |
||
111 | ); |
||
112 | |||
113 | // Do any third-party scripts want in on the fun? |
||
114 | call_integration_hook('integrate_autoload', array(&$classMap)); |
||
115 | |||
116 | foreach ($classMap as $prefix => $dirName) |
||
117 | { |
||
118 | // does the class use the namespace prefix? |
||
119 | $len = strlen($prefix); |
||
120 | if (strncmp($prefix, $class, $len) !== 0) |
||
121 | { |
||
122 | continue; |
||
123 | } |
||
124 | |||
125 | // get the relative class name |
||
126 | $relativeClass = substr($class, $len); |
||
127 | |||
128 | // replace the namespace prefix with the base directory, replace namespace |
||
129 | // separators with directory separators in the relative class name, append |
||
130 | // with .php |
||
131 | $fileName = $dirName . strtr($relativeClass, '\\', '/') . '.php'; |
||
132 | |||
133 | // if the file exists, require it |
||
134 | if (file_exists($fileName = $sourcedir . '/' . $fileName)) |
||
135 | { |
||
136 | require_once $fileName; |
||
137 | |||
138 | return; |
||
139 | } |
||
140 | } |
||
141 | }); |
||
142 | |||
143 | // Register an error handler. |
||
144 | set_error_handler('smf_error_handler'); |
||
145 | |||
146 | // Start the session. (assuming it hasn't already been.) |
||
147 | loadSession(); |
||
148 | |||
149 | // What function shall we execute? (done like this for memory's sake.) |
||
150 | call_user_func(smf_main()); |
||
151 | |||
152 | // Call obExit specially; we're coming from the main area ;). |
||
153 | obExit(null, null, true); |
||
154 | |||
155 | /** |
||
156 | * The main dispatcher. |
||
157 | * This delegates to each area. |
||
158 | * @return array|string|void An array containing the file to include and name of function to call, the name of a function to call or dies with a fatal_lang_error if we couldn't find anything to do. |
||
0 ignored issues
–
show
|
|||
159 | */ |
||
160 | function smf_main() |
||
161 | { |
||
162 | global $modSettings, $settings, $user_info, $board, $topic; |
||
0 ignored issues
–
show
Compatibility
Best Practice
introduced
by
Use of
global functionality is not recommended; it makes your code harder to test, and less reusable.
Instead of relying on 1. Pass all data via parametersfunction myFunction($a, $b) {
// Do something
}
2. Create a class that maintains your stateclass MyClass {
private $a;
private $b;
public function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
public function myFunction() {
// Do something
}
}
![]() |
|||
163 | global $board_info, $maintenance, $sourcedir; |
||
0 ignored issues
–
show
Compatibility
Best Practice
introduced
by
Use of
global functionality is not recommended; it makes your code harder to test, and less reusable.
Instead of relying on 1. Pass all data via parametersfunction myFunction($a, $b) {
// Do something
}
2. Create a class that maintains your stateclass MyClass {
private $a;
private $b;
public function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
public function myFunction() {
// Do something
}
}
![]() |
|||
164 | |||
165 | // Special case: session keep-alive, output a transparent pixel. |
||
166 | if (isset($_GET['action']) && $_GET['action'] == 'keepalive') |
||
167 | { |
||
168 | header('Content-Type: image/gif'); |
||
169 | die("\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x21\xF9\x04\x01\x00\x00\x00\x00\x2C\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02\x44\x01\x00\x3B"); |
||
170 | } |
||
171 | |||
172 | // We should set our security headers now. |
||
173 | frameOptionsHeader(); |
||
174 | |||
175 | // Load the user's cookie (or set as guest) and load their settings. |
||
176 | loadUserSettings(); |
||
177 | |||
178 | // Load the current board's information. |
||
179 | loadBoard(); |
||
180 | |||
181 | // Load the current user's permissions. |
||
182 | loadPermissions(); |
||
183 | |||
184 | // Attachments don't require the entire theme to be loaded. |
||
185 | if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'dlattach') |
||
186 | detectBrowser(); |
||
187 | // Load the current theme. (note that ?theme=1 will also work, may be used for guest theming.) |
||
188 | else |
||
189 | loadTheme(); |
||
190 | |||
191 | // Check if the user should be disallowed access. |
||
192 | is_not_banned(); |
||
193 | |||
194 | // If we are in a topic and don't have permission to approve it then duck out now. |
||
195 | if (!empty($topic) && empty($board_info['cur_topic_approved']) && !allowedTo('approve_posts') && ($user_info['id'] != $board_info['cur_topic_starter'] || $user_info['is_guest'])) |
||
196 | fatal_lang_error('not_a_topic', false); |
||
197 | |||
198 | $no_stat_actions = array('clock', 'dlattach', 'findmember', 'jsoption', 'likes', 'loadeditorlocale', 'modifycat', 'requestmembers', 'smstats', 'suggest', 'about:unknown', '.xml', 'xmlhttp', 'verificationcode', 'viewquery', 'viewsmfile'); |
||
199 | call_integration_hook('integrate_pre_log_stats', array(&$no_stat_actions)); |
||
200 | // Do some logging, unless this is an attachment, avatar, toggle of editor buttons, theme option, XML feed etc. |
||
201 | if (empty($_REQUEST['action']) || !in_array($_REQUEST['action'], $no_stat_actions)) |
||
202 | { |
||
203 | // Log this user as online. |
||
204 | writeLog(); |
||
205 | |||
206 | // Track forum statistics and hits...? |
||
207 | if (!empty($modSettings['hitStats'])) |
||
208 | trackStats(array('hits' => '+')); |
||
209 | } |
||
210 | unset($no_stat_actions); |
||
211 | |||
212 | // Is the forum in maintenance mode? (doesn't apply to administrators.) |
||
213 | if (!empty($maintenance) && !allowedTo('admin_forum')) |
||
214 | { |
||
215 | // You can only login.... otherwise, you're getting the "maintenance mode" display. |
||
216 | if (isset($_REQUEST['action']) && (in_array($_REQUEST['action'], array('login2', 'logintfa', 'logout')))) |
||
217 | { |
||
218 | require_once($sourcedir . '/LogInOut.php'); |
||
219 | return ($_REQUEST['action'] == 'login2' ? 'Login2' : ($_REQUEST['action'] == 'logintfa' ? 'LoginTFA' : 'Logout')); |
||
220 | } |
||
221 | // Don't even try it, sonny. |
||
222 | else |
||
223 | return 'InMaintenance'; |
||
224 | } |
||
225 | // If guest access is off, a guest can only do one of the very few following actions. |
||
226 | elseif (empty($modSettings['allow_guestAccess']) && $user_info['is_guest'] && (!isset($_REQUEST['action']) || !in_array($_REQUEST['action'], array('coppa', 'login', 'login2', 'logintfa', 'reminder', 'activate', 'help', 'helpadmin', 'smstats', 'verificationcode', 'signup', 'signup2')))) |
||
227 | return 'KickGuest'; |
||
228 | elseif (empty($_REQUEST['action'])) |
||
229 | { |
||
230 | // Action and board are both empty... BoardIndex! Unless someone else wants to do something different. |
||
231 | if (empty($board) && empty($topic)) |
||
232 | { |
||
233 | if (!empty($modSettings['integrate_default_action'])) |
||
234 | { |
||
235 | $defaultAction = explode(',', $modSettings['integrate_default_action']); |
||
236 | |||
237 | // Sorry, only one default action is needed. |
||
238 | $defaultAction = $defaultAction[0]; |
||
239 | |||
240 | $call = call_helper($defaultAction, true); |
||
241 | |||
242 | if (!empty($call)) |
||
243 | return $call; |
||
244 | } |
||
245 | |||
246 | // No default action huh? then go to our good old BoardIndex. |
||
247 | else |
||
248 | { |
||
249 | require_once($sourcedir . '/BoardIndex.php'); |
||
250 | |||
251 | return 'BoardIndex'; |
||
252 | } |
||
253 | } |
||
254 | |||
255 | // Topic is empty, and action is empty.... MessageIndex! |
||
256 | elseif (empty($topic)) |
||
257 | { |
||
258 | require_once($sourcedir . '/MessageIndex.php'); |
||
259 | return 'MessageIndex'; |
||
260 | } |
||
261 | |||
262 | // Board is not empty... topic is not empty... action is empty.. Display! |
||
263 | else |
||
264 | { |
||
265 | require_once($sourcedir . '/Display.php'); |
||
266 | return 'Display'; |
||
267 | } |
||
268 | } |
||
269 | |||
270 | // Here's the monstrous $_REQUEST['action'] array - $_REQUEST['action'] => array($file, $function). |
||
271 | $actionArray = array( |
||
272 | 'activate' => array('Register.php', 'Activate'), |
||
273 | 'admin' => array('Admin.php', 'AdminMain'), |
||
274 | 'announce' => array('Post.php', 'AnnounceTopic'), |
||
275 | 'attachapprove' => array('ManageAttachments.php', 'ApproveAttach'), |
||
276 | 'buddy' => array('Subs-Members.php', 'BuddyListToggle'), |
||
277 | 'calendar' => array('Calendar.php', 'CalendarMain'), |
||
278 | 'clock' => array('Calendar.php', 'clock'), |
||
279 | 'coppa' => array('Register.php', 'CoppaForm'), |
||
280 | 'credits' => array('Who.php', 'Credits'), |
||
281 | 'deletemsg' => array('RemoveTopic.php', 'DeleteMessage'), |
||
282 | 'dlattach' => array('ShowAttachments.php', 'showAttachment'), |
||
283 | 'editpoll' => array('Poll.php', 'EditPoll'), |
||
284 | 'editpoll2' => array('Poll.php', 'EditPoll2'), |
||
285 | 'findmember' => array('Subs-Auth.php', 'JSMembers'), |
||
286 | 'groups' => array('Groups.php', 'Groups'), |
||
287 | 'help' => array('Help.php', 'ShowHelp'), |
||
288 | 'helpadmin' => array('Help.php', 'ShowAdminHelp'), |
||
289 | 'jsmodify' => array('Post.php', 'JavaScriptModify'), |
||
290 | 'jsoption' => array('Themes.php', 'SetJavaScript'), |
||
291 | 'likes' => array('Likes.php', 'Likes::call#'), |
||
292 | 'loadeditorlocale' => array('Subs-Editor.php', 'loadLocale'), |
||
293 | 'lock' => array('Topic.php', 'LockTopic'), |
||
294 | 'lockvoting' => array('Poll.php', 'LockVoting'), |
||
295 | 'login' => array('LogInOut.php', 'Login'), |
||
296 | 'login2' => array('LogInOut.php', 'Login2'), |
||
297 | 'logintfa' => array('LogInOut.php', 'LoginTFA'), |
||
298 | 'logout' => array('LogInOut.php', 'Logout'), |
||
299 | 'markasread' => array('Subs-Boards.php', 'MarkRead'), |
||
300 | 'mergetopics' => array('SplitTopics.php', 'MergeTopics'), |
||
301 | 'mlist' => array('Memberlist.php', 'Memberlist'), |
||
302 | 'moderate' => array('ModerationCenter.php', 'ModerationMain'), |
||
303 | 'modifycat' => array('ManageBoards.php', 'ModifyCat'), |
||
304 | 'movetopic' => array('MoveTopic.php', 'MoveTopic'), |
||
305 | 'movetopic2' => array('MoveTopic.php', 'MoveTopic2'), |
||
306 | 'notify' => array('Notify.php', 'Notify'), |
||
307 | 'notifyboard' => array('Notify.php', 'BoardNotify'), |
||
308 | 'notifytopic' => array('Notify.php', 'TopicNotify'), |
||
309 | 'pm' => array('PersonalMessage.php', 'MessageMain'), |
||
310 | 'post' => array('Post.php', 'Post'), |
||
311 | 'post2' => array('Post.php', 'Post2'), |
||
312 | 'printpage' => array('Printpage.php', 'PrintTopic'), |
||
313 | 'profile' => array('Profile.php', 'ModifyProfile'), |
||
314 | 'quotefast' => array('Post.php', 'QuoteFast'), |
||
315 | 'quickmod' => array('MessageIndex.php', 'QuickModeration'), |
||
316 | 'quickmod2' => array('Display.php', 'QuickInTopicModeration'), |
||
317 | 'recent' => array('Recent.php', 'RecentPosts'), |
||
318 | 'reminder' => array('Reminder.php', 'RemindMe'), |
||
319 | 'removepoll' => array('Poll.php', 'RemovePoll'), |
||
320 | 'removetopic2' => array('RemoveTopic.php', 'RemoveTopic2'), |
||
321 | 'reporttm' => array('ReportToMod.php', 'ReportToModerator'), |
||
322 | 'requestmembers' => array('Subs-Auth.php', 'RequestMembers'), |
||
323 | 'restoretopic' => array('RemoveTopic.php', 'RestoreTopic'), |
||
324 | 'search' => array('Search.php', 'PlushSearch1'), |
||
325 | 'search2' => array('Search.php', 'PlushSearch2'), |
||
326 | 'sendactivation' => array('Register.php', 'SendActivation'), |
||
327 | 'signup' => array('Register.php', 'Register'), |
||
328 | 'signup2' => array('Register.php', 'Register2'), |
||
329 | 'smstats' => array('Stats.php', 'SMStats'), |
||
330 | 'suggest' => array('Subs-Editor.php', 'AutoSuggestHandler'), |
||
331 | 'spellcheck' => array('Subs-Post.php', 'SpellCheck'), |
||
332 | 'splittopics' => array('SplitTopics.php', 'SplitTopics'), |
||
333 | 'stats' => array('Stats.php', 'DisplayStats'), |
||
334 | 'sticky' => array('Topic.php', 'Sticky'), |
||
335 | 'theme' => array('Themes.php', 'ThemesMain'), |
||
336 | 'trackip' => array('Profile-View.php', 'trackIP'), |
||
337 | 'about:unknown' => array('Likes.php', 'BookOfUnknown'), |
||
338 | 'unread' => array('Recent.php', 'UnreadTopics'), |
||
339 | 'unreadreplies' => array('Recent.php', 'UnreadTopics'), |
||
340 | 'uploadAttach' => array('Attachments.php', 'Attachments::call#'), |
||
341 | 'verificationcode' => array('Register.php', 'VerificationCode'), |
||
342 | 'viewprofile' => array('Profile.php', 'ModifyProfile'), |
||
343 | 'vote' => array('Poll.php', 'Vote'), |
||
344 | 'viewquery' => array('ViewQuery.php', 'ViewQuery'), |
||
345 | 'viewsmfile' => array('Admin.php', 'DisplayAdminFile'), |
||
346 | 'who' => array('Who.php', 'Who'), |
||
347 | '.xml' => array('News.php', 'ShowXmlFeed'), |
||
348 | 'xmlhttp' => array('Xml.php', 'XMLhttpMain'), |
||
349 | ); |
||
350 | |||
351 | // Allow modifying $actionArray easily. |
||
352 | call_integration_hook('integrate_actions', array(&$actionArray)); |
||
353 | |||
354 | // Get the function and file to include - if it's not there, do the board index. |
||
355 | if (!isset($_REQUEST['action']) || !isset($actionArray[$_REQUEST['action']])) |
||
356 | { |
||
357 | // Catch the action with the theme? |
||
358 | if (!empty($settings['catch_action'])) |
||
359 | { |
||
360 | require_once($sourcedir . '/Themes.php'); |
||
361 | return 'WrapAction'; |
||
362 | } |
||
363 | |||
364 | if (!empty($modSettings['integrate_fallback_action'])) |
||
365 | { |
||
366 | $fallbackAction = explode(',', $modSettings['integrate_fallback_action']); |
||
367 | |||
368 | // Sorry, only one fallback action is needed. |
||
369 | $fallbackAction = $fallbackAction[0]; |
||
370 | |||
371 | $call = call_helper($fallbackAction, true); |
||
372 | |||
373 | if (!empty($call)) |
||
374 | return $call; |
||
375 | } |
||
376 | |||
377 | // No fallback action, huh? |
||
378 | else |
||
379 | { |
||
380 | fatal_lang_error('not_found', false, array(), 404); |
||
381 | } |
||
382 | } |
||
383 | |||
384 | // Otherwise, it was set - so let's go to that action. |
||
385 | if (!empty($actionArray[$_REQUEST['action']][0])) |
||
386 | require_once($sourcedir . '/' . $actionArray[$_REQUEST['action']][0]); |
||
387 | |||
388 | // Do the right thing. |
||
389 | return call_helper($actionArray[$_REQUEST['action']][1], true); |
||
390 | } |
||
391 | |||
392 | ?> |
This check compares the return type specified in the
@return
annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.If the return type contains the type array, this check recommends the use of a more specific type like
String[]
orarray<String>
.