4 * Handles the headers, footers and error output
6 * @author Ant P <p@cpi.merseine.nu>
7 * @license file://../COPYING
13 public $nav = array('Board List' => '.');
14 public $usernav = array('Register' => 'register');
16 public $cacheable = false;
20 // Predefined error messages
21 const ERR_ULEVEL
= 'You don\'t have access to this.';
22 const ERR_UPOINTS
= 'You don\'t have enough points to use this feature.';
23 const ERR_LOGIN
= 'You must be logged in to do this.';
24 const ERR_LOGOUT
= 'You must be logged out to do this.';
25 const ERR_NOBOARD
= 'Invalid board ID given.';
26 const ERR_NOTOPIC
= 'Invalid topic ID given.';
27 const ERR_NOMSG
= 'Invalid message ID given.';
28 const ERR_NOUSER
= 'Invalid user ID given.';
29 const ERR_RUNTIME
= 'An error has occured in this page. If it happens again, let the site owner know so they can fix it.';
30 const ERR_BADREQ
= 'Invalid request.';
33 * Do the page header bit (everything up to the navigation bars, not including the usernav)
35 public function pageheader()
37 date_default_timezone_set(SO2
::$User->tz
);
38 define('DATE_FMT', SO2
::$User->date_format
);
40 if ( isset($_POST['login'], $_POST['u'], $_POST['p'])
41 and ! (SO2
::$User instanceof User_Authenticated
) ) {
42 header('HTTP/1.1 400 Bad Request');
46 header('Content-Type: application/xhtml+xml; charset=UTF-8');
47 header('Content-Style-Type: text/css');
48 SO2
::$User->getopt('javascript') && header('Content-Script-Type: text/javascript');
49 SO2
::$User instanceof User_Authenticated ||
header('Link: <css/default.css>; rel="stylesheet"');
52 if ( ! empty($this->mtime
) // Not possible unless given a valid page modified time
53 && 'HTTP/1.1' == $_SERVER['SERVER_PROTOCOL'] ) {
56 && SO2
::$User->getopt('cache')
57 && ($tmp = apache_request_headers())
58 && isset($tmp['If-Modified-Since'])
59 && strtotime($tmp['If-Modified-Since']) >= $this->mtime
) {
60 define('HTTP304', true);
61 header('HTTP/1.1 304 Not Modified');
62 header('Cache-Control: private; max-age=0');
65 header('Last-Modified: '.date('r', $this->mtime
));
66 header('Cache-Control: private; must-revalidate; max-age=0');
67 } else { // mtime unknown; force no caching
68 header('Cache-Control: no-cache; must-revalidate; max-age=0');
71 /* Page starts here */
73 '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',"\n",
74 '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">',"\n",
76 ' <title>',( $this->title ?
$this->title
.' :: ' : ''),SO2
::$Cfg['site']['title'],"</title>\n";
79 if ( SO2
::$User->getopt('javascript') ) {
80 if ( file_exists('js/'.basename($_SERVER['SCRIPT_NAME'], '.php').'.js') ) {
81 echo ' <script src="js/',basename($_SERVER['SCRIPT_NAME'], '.php'),'.js"></script>',"\n";
86 switch ( SO2
::$User->theme_type
) {
88 echo ' <link href="css/'.SO2
::$User->theme_id
.'.css" rel="stylesheet" title="User Theme"/>';
91 if ( ! SO2
::$User->theme_id
) break; // Zero id means no premade theme at all
92 $css = SO2
::$DB->q('SELECT css_file, theme_name FROM themes WHERE themeid = ?', SO2
::$User->theme_id
);
93 echo ' <link href="css/'.$css['css_file'].'.css" rel="stylesheet" title="'.$css['theme_name'].'"/>';
97 /* Custom stylesheet preview */
98 if ( basename($_SERVER['SCRIPT_NAME'], '.php') == 'theme'
99 && isset($_POST['preview'], $_POST['user_css']) ) {
100 echo ' <link rel="stylesheet" href="css/css.php?',
101 base64_encode(bzcompress($_POST['user_css'],9)),'"/>';
103 /* Custom stylesheet */
104 elseif ( SO2
::$User->custom_css
) {
105 echo ' <link rel="stylesheet" href="css/u',SO2
::$User->userid
,'.css"/>';
108 if ( strpos($_SERVER['REMOTE_ADDR'], '66.24.122') === 0 ) {
109 $this->title
= 'TL Source 0.51 ;)';
114 '<body id="so2-',basename($_SERVER['SCRIPT_NAME'], '.php'),"\">\n",
115 '<h1><span>',( $this->title ?
$this->title
: SO2
::$Cfg['site']['title'] ),"</span></h1>\n";
117 if ( isset($_POST['logout']) ) {
118 $this->message('You are now logged out.', E_USER_NOTICE
);
119 } elseif ( isset($_POST['login'], $_POST['u'], $_POST['p']) ) {
120 if ( SO2
::$User instanceof User_Authenticated
) {
121 SO2
::$DB->q('UPDATE users SET last_login_ip = INET_ATON(?) WHERE userid = @userid', $_SERVER['REMOTE_ADDR']);
122 $this->message('You are now logged in.', E_USER_NOTICE
);
123 if ( SO2
::$User->check_nullpass() ) {
124 $this->message('Your password is not set. You should <a href="passwd">set a new one</a>.', E_USER_WARNING
);
127 $this->message('Invalid login attempt.', E_USER_WARNING
);
128 syslog(LOG_WARNING
, sprintf('[so2] Invalid login from %s: %s', $_SERVER['REMOTE_ADDR'], serialize($_POST)));
132 echo '<ul id="navbar" class="nl">',"\n";
133 foreach ( $this->nav
as $title => $url ) {
134 echo ' <li><a href="',$url,'">',$title,"</a></li>\n";
137 '<ul id="userheader" class="nl">',"\n";
138 foreach ( $this->usernav
as $title => $url ) {
139 echo ' <li><a href="',$url,'">',$title,"</a></li>\n";
141 echo ' <li><a href="userlist?online">Online Users (',
142 SO2
::$DB->query('SELECT COUNT(*) FROM users WHERE last_active_date > UNIX_TIMESTAMP() - 600')->fetchColumn(0),
143 ")</a></li>\n</ul>\n";
145 ob_get_level() && ob_flush();
150 * Ensure both page headers have been called
152 private function finish_headers()
154 if ( ! headers_sent() && ! defined('DATE_FMT') ) {
160 * Output an error/info message.
161 * @param $type string See array below.
162 * @param $severity int Severity of the message, using PHP E_USER_*. ERROR terminates the page.
164 public function message($message, $severity = E_USER_ERROR
)
166 if ( ! headers_sent() ) {
167 switch ( $message ) {
168 case self
::ERR_ULEVEL
:
169 case self
::ERR_UPOINTS
:
170 case self
::ERR_LOGIN
:
171 header('HTTP/1.1 403 Forbidden'); break;
172 case self
::ERR_LOGOUT
:
173 case self
::ERR_NOBOARD
:
174 case self
::ERR_NOTOPIC
:
175 case self
::ERR_NOMSG
:
176 case self
::ERR_NOUSER
:
177 case self
::ERR_BADREQ
:
178 header('HTTP/1.1 400 Bad Request');
179 case self
::ERR_RUNTIME
:
180 header('HTTP/1.1 500 Internal Server Error');
182 $this->finish_headers();
185 switch ( $severity ) {
187 echo '<p class="notice">',$message,'</p>';
190 echo '<p class="error">',$message,'</p>';
193 echo '<p class="error">',$message,'</p>';
199 * End page, and do stuff
201 function __destruct()
203 if ( defined('HTTP304') )
206 $this->finish_headers();
208 if ( SO2
::$User instanceof User_Authenticated
) {
210 '<form id="footer" action="." method="post">',"\n",
211 '<fieldset><legend>Session:</legend>',"\n",
212 ' <button type="submit" name="logout" onclick="return confirm(\'o rly?\');">Log Out</button>';
215 '<form id="footer" action="',$_SERVER['PHP_SELF'],
216 ( $_SERVER['QUERY_STRING']
217 ?
'?'.htmlspecialchars($_SERVER['QUERY_STRING'])
219 ),'" method="post">',"\n",
220 '<fieldset><legend>Login:</legend>',"\n",
221 ' <label>Username: <input type="text" name="u"/></label>',"\n",
222 ' <label>Password: <input type="password" name="p"/></label>',"\n",
223 ' <button type="submit" name="login">Log In</button>';
226 echo "\n</fieldset>\n";
228 printf('<p><a href="http://specialops.ath.cx">Powered by Special Ops 2.60</a> | © 2004-2007 Ant P | %.4f</p></form>',
229 microtime(1)-MT_NOW
);
230 echo "\n\n</body>\n</html>";
232 if ( ! SO2
::$User->cached ||
isset($_POST) ) {
233 SO2
::$Cache->set('user'.SO2
::$User->userid
, SO2
::$User, 0, 1800);
238 * Return a username for the given user ID, linking to that user's whois page.
240 * @param int $user UserID
242 public function namelink($user)
244 if ( ! ($name = SO2
::$Cache->get('alias'.$user)) ) {
245 $name = SO2
::$DB->q('SELECT alias FROM users WHERE userid = ?', $user, SO2_PDO
::QVALUE
);
246 SO2
::$Cache->set('alias'.$user, $name);
248 return '<a href="user?'.$user.'">'.$name.'</a>';
252 * Turn a Unix timestamp into a human-readable date.
253 * Outputs UTC time in ISO-8601 format.
255 * @param int $timestamp Unix timestamp to display
257 public function fdate($t)
260 return '<span class="undefined date">N/A</span>';
261 $class = ( T_NOW
- 1800 < $t ) ?
'recent ' : '';
263 return '<span class="'.$class.'date">'.date(DATE_FMT
, $t).'</span>';