21 * @license GNU General Public License <http://www.gnu.org/licenses/gpl-2.0.html> |
21 * @license GNU General Public License <http://www.gnu.org/licenses/gpl-2.0.html> |
22 */ |
22 */ |
23 |
23 |
24 class PageProcessor |
24 class PageProcessor |
25 { |
25 { |
26 |
26 |
27 /** |
27 /** |
28 * Page ID and namespace of the page handled by this instance |
28 * Page ID and namespace of the page handled by this instance |
29 * @var string |
29 * @var string |
30 */ |
30 */ |
31 |
31 |
32 var $page_id; |
32 var $page_id; |
33 var $namespace; |
33 var $namespace; |
34 |
34 |
35 /** |
35 /** |
36 * The instance of the namespace processor for the namespace we're doing. |
36 * The instance of the namespace processor for the namespace we're doing. |
37 * @var object |
37 * @var object |
38 */ |
38 */ |
39 |
39 |
40 var $ns; |
40 var $ns; |
41 |
41 |
42 /** |
42 /** |
43 * The title of the page sent to the template parser |
43 * The title of the page sent to the template parser |
44 * @var string |
44 * @var string |
45 */ |
45 */ |
46 |
46 |
47 var $title = ''; |
47 var $title = ''; |
48 |
48 |
49 /** |
49 /** |
50 * The information about the page(s) we were redirected from |
50 * The information about the page(s) we were redirected from |
51 * @var array |
51 * @var array |
52 */ |
52 */ |
53 |
53 |
54 var $redirect_stack = array(); |
54 var $redirect_stack = array(); |
55 |
55 |
56 /** |
56 /** |
57 * The revision ID (history entry) to send. If set to 0 (the default) then the most recent revision will be sent. |
57 * The revision ID (history entry) to send. If set to 0 (the default) then the most recent revision will be sent. |
58 * @var int |
58 * @var int |
59 */ |
59 */ |
60 |
60 |
61 var $revision_id = 0; |
61 var $revision_id = 0; |
62 |
62 |
63 /** |
63 /** |
64 * The time this revision was saved, as a UNIX timestamp |
64 * The time this revision was saved, as a UNIX timestamp |
65 * @var int |
65 * @var int |
66 */ |
66 */ |
67 |
67 |
68 var $revision_time = 0; |
68 var $revision_time = 0; |
69 |
69 |
70 /** |
70 /** |
71 * Unsanitized page ID. |
71 * Unsanitized page ID. |
72 * @var string |
72 * @var string |
73 */ |
73 */ |
74 |
74 |
75 var $page_id_unclean; |
75 var $page_id_unclean; |
76 |
76 |
77 /** |
77 /** |
78 * Tracks if the page we're loading exists in the database or not. |
78 * Tracks if the page we're loading exists in the database or not. |
79 * @var bool |
79 * @var bool |
80 */ |
80 */ |
81 |
81 |
82 var $page_exists = false; |
82 var $page_exists = false; |
83 |
83 |
84 /** |
84 /** |
85 * Permissions! |
85 * Permissions! |
86 * @var object |
86 * @var object |
87 */ |
87 */ |
88 |
88 |
89 var $perms = null; |
89 var $perms = null; |
90 |
90 |
91 /** |
91 /** |
92 * The SHA1 hash of the user-inputted password for the page |
92 * The SHA1 hash of the user-inputted password for the page |
93 * @var string |
93 * @var string |
94 */ |
94 */ |
95 |
95 |
96 var $password = ''; |
96 var $password = ''; |
97 |
97 |
98 /** |
98 /** |
99 * Switch to track if redirects are allowed. Defaults to true. |
99 * Switch to track if redirects are allowed. Defaults to true. |
100 * @var bool |
100 * @var bool |
101 */ |
101 */ |
102 |
102 |
103 var $allow_redir = true; |
103 var $allow_redir = true; |
104 |
104 |
105 /** |
105 /** |
106 * Holds any error message from redirection code. Defaults to false (no error). |
106 * Holds any error message from redirection code. Defaults to false (no error). |
107 * @var mixed |
107 * @var mixed |
108 */ |
108 */ |
109 |
109 |
110 var $redir_error = false; |
110 var $redir_error = false; |
111 |
111 |
112 /** |
112 /** |
113 * If this is set to true, this will call the header and footer funcs on $template when render() is called. |
113 * If this is set to true, this will call the header and footer funcs on $template when render() is called. |
114 * @var bool |
114 * @var bool |
115 */ |
115 */ |
116 |
116 |
117 var $send_headers = false; |
117 var $send_headers = false; |
118 |
118 |
119 /** |
119 /** |
120 * Cache the fetched text so we don't fetch it from the DB twice. |
120 * Cache the fetched text so we don't fetch it from the DB twice. |
121 * @var string |
121 * @var string |
122 */ |
122 */ |
123 |
123 |
124 var $text_cache = ''; |
124 var $text_cache = ''; |
125 |
125 |
126 /** |
126 /** |
127 * Debugging information to track errors. You can set enable to false to disable sending debug information. |
127 * Debugging information to track errors. You can set enable to false to disable sending debug information. |
128 * @var array |
128 * @var array |
129 */ |
129 */ |
130 |
130 |
131 var $debug = array( |
131 var $debug = array( |
132 'enable' => false, |
132 'enable' => false, |
133 'works' => false |
133 'works' => false |
134 ); |
134 ); |
135 |
135 |
136 /** |
136 /** |
137 * The list of errors raised in the class. |
137 * The list of errors raised in the class. |
138 * @var array |
138 * @var array |
139 */ |
139 */ |
140 |
140 |
141 var $_errors = array(); |
141 var $_errors = array(); |
142 |
142 |
143 /** |
143 /** |
144 * Constructor. |
144 * Constructor. |
145 * @param string The page ID (urlname) of the page |
145 * @param string The page ID (urlname) of the page |
146 * @param string The namespace of the page |
146 * @param string The namespace of the page |
147 * @param int Optional. The revision ID to send. |
147 * @param int Optional. The revision ID to send. |
148 */ |
148 */ |
149 |
149 |
150 function __construct( $page_id, $namespace, $revision_id = 0 ) |
150 function __construct( $page_id, $namespace, $revision_id = 0 ) |
151 { |
151 { |
152 global $db, $session, $paths, $template, $plugins; // Common objects |
152 global $db, $session, $paths, $template, $plugins; // Common objects |
153 |
153 |
154 profiler_log("PageProcessor [{$namespace}:{$page_id}]: Started constructor"); |
154 profiler_log("PageProcessor [{$namespace}:{$page_id}]: Started constructor"); |
155 |
155 |
156 // See if we can get some debug info |
156 // See if we can get some debug info |
157 if ( function_exists('debug_backtrace') && $this->debug['enable'] ) |
157 if ( function_exists('debug_backtrace') && $this->debug['enable'] ) |
158 { |
158 { |
159 $this->debug['works'] = true; |
159 $this->debug['works'] = true; |
160 $this->debug['backtrace'] = enano_debug_print_backtrace(true); |
160 $this->debug['backtrace'] = enano_debug_print_backtrace(true); |
161 } |
161 } |
162 |
162 |
163 // First things first - check page existence and permissions |
163 // First things first - check page existence and permissions |
164 |
164 |
165 if ( !isset($paths->nslist[$namespace]) ) |
165 if ( !isset($paths->nslist[$namespace]) ) |
166 { |
166 { |
167 $this->send_error('The namespace "' . htmlspecialchars($namespace) . '" does not exist.'); |
167 $this->send_error('The namespace "' . htmlspecialchars($namespace) . '" does not exist.'); |
168 } |
168 } |
169 |
169 |
170 if ( !is_int($revision_id) ) |
170 if ( !is_int($revision_id) ) |
171 $revision_id = 0; |
171 $revision_id = 0; |
172 |
172 |
173 $this->_setup( $page_id, $namespace, $revision_id ); |
173 $this->_setup( $page_id, $namespace, $revision_id ); |
174 } |
174 } |
175 |
175 |
176 /** |
176 /** |
177 * The main method to send the page content. Also responsible for checking permissions and calling the statistics counter. |
177 * The main method to send the page content. Also responsible for checking permissions and calling the statistics counter. |
178 * @param bool If true, the stat counter is called. Defaults to false. |
178 * @param bool If true, the stat counter is called. Defaults to false. |
179 */ |
179 */ |
180 |
180 |
181 function send( $do_stats = false ) |
181 function send( $do_stats = false ) |
182 { |
182 { |
183 global $db, $session, $paths, $template, $plugins; // Common objects |
183 global $db, $session, $paths, $template, $plugins; // Common objects |
184 global $lang, $output; |
184 global $lang, $output; |
185 |
185 |
186 profiler_log('PageProcessor: send() called'); |
186 profiler_log('PageProcessor: send() called'); |
187 |
187 |
188 if ( !$this->perms->get_permissions('read') ) |
188 if ( !$this->perms->get_permissions('read') ) |
189 { |
189 { |
190 // Permission denied to read page. Is this one of our core pages that must always be allowed? |
190 // Permission denied to read page. Is this one of our core pages that must always be allowed? |
191 // NOTE: Not even the administration panel will work if ACLs deny access to it. |
191 // NOTE: Not even the administration panel will work if ACLs deny access to it. |
192 if ( $this->namespace == 'Special' && in_array($this->page_id, array('Login', 'Logout', 'LangExportJSON', 'CSS')) ) |
192 if ( $this->namespace == 'Special' && in_array($this->page_id, array('Login', 'Logout', 'LangExportJSON', 'CSS')) ) |
193 { |
193 { |
194 // Do nothing; allow execution to continue |
194 // Do nothing; allow execution to continue |
195 } |
195 } |
196 else |
196 else |
197 { |
197 { |
198 // Page isn't whitelisted, behave as normal |
198 // Page isn't whitelisted, behave as normal |
199 $this->err_access_denied(); |
199 $this->err_access_denied(); |
200 return false; |
200 return false; |
201 } |
201 } |
202 } |
202 } |
203 if ( $this->revision_id > 0 && !$this->perms->get_permissions('history_view') ) |
203 if ( $this->revision_id > 0 && !$this->perms->get_permissions('history_view') ) |
204 { |
204 { |
205 $this->err_access_denied(); |
205 $this->err_access_denied(); |
206 return false; |
206 return false; |
207 } |
207 } |
208 |
208 |
209 // Is there a custom function registered for handling this namespace? |
209 // Is there a custom function registered for handling this namespace? |
210 // DEPRECATED (even though it only saw its way into one alpha release.) |
210 // DEPRECATED (even though it only saw its way into one alpha release.) |
211 if ( $proc = $paths->get_namespace_processor($this->namespace) ) |
211 if ( $proc = $paths->get_namespace_processor($this->namespace) ) |
212 { |
212 { |
213 // yes, just call that |
213 // yes, just call that |
214 // this is protected aggressively by the PathManager against overriding critical namespaces |
214 // this is protected aggressively by the PathManager against overriding critical namespaces |
215 return call_user_func($proc, $this); |
215 return call_user_func($proc, $this); |
216 } |
216 } |
217 |
217 |
218 $pathskey = $paths->nslist[ $this->namespace ] . $this->page_id; |
218 $pathskey = $paths->nslist[ $this->namespace ] . $this->page_id; |
219 $strict_no_headers = false; |
219 $strict_no_headers = false; |
220 $admin_fail = false; |
220 $admin_fail = false; |
221 if ( $this->namespace == 'Admin' && strstr($this->page_id, '/') ) |
221 if ( $this->namespace == 'Admin' && strstr($this->page_id, '/') ) |
222 { |
222 { |
223 $this->page_id = substr($this->page_id, 0, strpos($this->page_id, '/')); |
223 $this->page_id = substr($this->page_id, 0, strpos($this->page_id, '/')); |
224 $funcname = "page_{$this->namespace}_{$this->page_id}"; |
224 $funcname = "page_{$this->namespace}_{$this->page_id}"; |
225 if ( function_exists($funcname) ) |
225 if ( function_exists($funcname) ) |
226 { |
226 { |
227 $this->page_exists = true; |
227 $this->page_exists = true; |
228 } |
228 } |
229 } |
229 } |
230 if ( isPage($pathskey) ) |
230 if ( isPage($pathskey) ) |
231 { |
231 { |
232 $cdata = $this->ns->get_cdata(); |
232 $cdata = $this->ns->get_cdata(); |
233 |
233 |
234 if ( $cdata['special'] == 1 ) |
234 if ( $cdata['special'] == 1 ) |
235 { |
235 { |
236 $this->send_headers = false; |
236 $this->send_headers = false; |
237 $strict_no_headers = true; |
237 $strict_no_headers = true; |
238 $GLOBALS['output'] = new Output_Naked(); |
238 $GLOBALS['output'] = new Output_Naked(); |
239 } |
239 } |
240 if ( isset($cdata['password']) ) |
240 if ( isset($cdata['password']) ) |
241 { |
241 { |
242 if ( $cdata['password'] != '' && $cdata['password'] != sha1('') ) |
242 if ( $cdata['password'] != '' && $cdata['password'] != sha1('') ) |
243 { |
243 { |
244 $password =& $cdata['password']; |
244 $password =& $cdata['password']; |
245 if ( $this->password != $password ) |
245 if ( $this->password != $password ) |
246 { |
246 { |
247 $this->err_wrong_password(); |
247 $this->err_wrong_password(); |
248 return false; |
248 return false; |
249 } |
249 } |
250 } |
250 } |
251 } |
251 } |
252 if ( isset($cdata['require_admin']) && $cdata['require_admin'] ) |
252 if ( isset($cdata['require_admin']) && $cdata['require_admin'] ) |
253 { |
253 { |
254 if ( $session->auth_level < USER_LEVEL_ADMIN ) |
254 if ( $session->auth_level < USER_LEVEL_ADMIN ) |
255 { |
255 { |
256 $admin_fail = true; |
256 $admin_fail = true; |
257 } |
257 } |
258 } |
258 } |
259 } |
259 } |
260 else if ( $this->namespace === $paths->namespace && $this->page_id == $paths->page_id ) |
260 else if ( $this->namespace === $paths->namespace && $this->page_id == $paths->page_id ) |
261 { |
261 { |
262 if ( isset($paths->cpage['require_admin']) && $paths->cpage['require_admin'] ) |
262 if ( isset($paths->cpage['require_admin']) && $paths->cpage['require_admin'] ) |
263 { |
263 { |
264 if ( $session->auth_level < USER_LEVEL_ADMIN ) |
264 if ( $session->auth_level < USER_LEVEL_ADMIN ) |
265 { |
265 { |
266 $admin_fail = true; |
266 $admin_fail = true; |
267 } |
267 } |
268 } |
268 } |
269 } |
269 } |
270 if ( $admin_fail ) |
270 if ( $admin_fail ) |
271 { |
271 { |
272 header('Content-type: text/javascript'); |
272 header('Content-type: text/javascript'); |
273 echo enano_json_encode(array( |
273 echo enano_json_encode(array( |
274 'mode' => 'error', |
274 'mode' => 'error', |
275 'error' => 'need_auth_to_admin' |
275 'error' => 'need_auth_to_admin' |
276 )); |
276 )); |
277 return true; |
277 return true; |
278 } |
278 } |
279 if ( $this->page_exists && $this->namespace != 'Special' && $this->namespace != 'Admin' && $do_stats ) |
279 if ( $this->page_exists && $this->namespace != 'Special' && $this->namespace != 'Admin' && $do_stats ) |
280 { |
280 { |
281 require_once(ENANO_ROOT.'/includes/stats.php'); |
281 require_once(ENANO_ROOT.'/includes/stats.php'); |
282 doStats($this->page_id, $this->namespace); |
282 doStats($this->page_id, $this->namespace); |
283 } |
283 } |
284 |
284 |
285 // We are all done. Ship off the page. |
285 // We are all done. Ship off the page. |
286 |
286 |
287 if ( !$this->allow_redir ) |
287 if ( !$this->allow_redir ) |
288 { |
288 { |
289 if ( method_exists($this->ns, 'get_redirect') ) |
289 if ( method_exists($this->ns, 'get_redirect') ) |
290 { |
290 { |
291 if ( $result = $this->ns->get_redirect() ) |
291 if ( $result = $this->ns->get_redirect() ) |
292 display_redirect_notice($result['page_id'], $result['namespace']); |
292 display_redirect_notice($result['page_id'], $result['namespace']); |
293 } |
293 } |
294 } |
294 } |
295 else |
295 else |
296 { |
296 { |
297 $this->process_redirects(); |
297 $this->process_redirects(); |
298 |
298 |
299 if ( count($this->redirect_stack) > 0 ) |
299 if ( count($this->redirect_stack) > 0 ) |
300 { |
300 { |
301 $stack = array_reverse($this->redirect_stack); |
301 $stack = array_reverse($this->redirect_stack); |
302 foreach ( $stack as $stackel ) |
302 foreach ( $stack as $stackel ) |
303 { |
303 { |
304 $url = makeUrlNS($stackel['old_namespace'], $stackel['old_page_id'], 'redirect=no', true); |
304 $url = makeUrlNS($stackel['old_namespace'], $stackel['old_page_id'], 'redirect=no', true); |
305 $page_data = $this->ns->get_cdata(); |
305 $page_data = $this->ns->get_cdata(); |
306 $title = $stackel['old_title']; |
306 $title = $stackel['old_title']; |
307 $a = '<a href="' . $url . '">' . htmlspecialchars($title) . '</a>'; |
307 $a = '<a href="' . $url . '">' . htmlspecialchars($title) . '</a>'; |
308 $output->add_after_header('<small>' . $lang->get('page_msg_redirected_from', array('from' => $a)) . '<br /></small>'); |
308 $output->add_after_header('<small>' . $lang->get('page_msg_redirected_from', array('from' => $a)) . '<br /></small>'); |
309 } |
309 } |
310 $template->set_page($this); |
310 $template->set_page($this); |
311 } |
311 } |
312 |
312 |
313 if ( $this->redir_error ) |
313 if ( $this->redir_error ) |
314 { |
314 { |
315 $output->add_after_header('<div class="usermessage"><b>' . $this->redir_error . '</b></div>'); |
315 $output->add_after_header('<div class="usermessage"><b>' . $this->redir_error . '</b></div>'); |
316 $result = $this->ns->get_redirect(); |
316 $result = $this->ns->get_redirect(); |
317 display_redirect_notice($result['page_id'], $result['namespace']); |
317 display_redirect_notice($result['page_id'], $result['namespace']); |
318 } |
318 } |
319 } |
319 } |
320 |
320 |
321 $this->ns->send(); |
321 $this->ns->send(); |
322 } |
322 } |
323 |
323 |
324 /** |
324 /** |
325 * Sends the page through by fetching it from the database. |
325 * Sends the page through by fetching it from the database. |
326 */ |
326 */ |
327 |
327 |
328 function send_from_db($strict_no_headers = false) |
328 function send_from_db($strict_no_headers = false) |
329 { |
329 { |
330 global $db, $session, $paths, $template, $plugins; // Common objects |
330 global $db, $session, $paths, $template, $plugins; // Common objects |
331 global $lang; |
331 global $lang; |
332 |
332 |
333 $this->ns->send_from_db(); |
333 $this->ns->send_from_db(); |
334 } |
334 } |
335 |
335 |
336 /** |
336 /** |
337 * Fetches the wikitext or HTML source for the page. |
337 * Fetches the wikitext or HTML source for the page. |
338 * @return string |
338 * @return string |
339 */ |
339 */ |
340 |
340 |
341 function fetch_source() |
341 function fetch_source() |
342 { |
342 { |
343 global $db, $session, $paths, $template, $plugins; // Common objects |
343 global $db, $session, $paths, $template, $plugins; // Common objects |
344 |
344 |
345 if ( !$this->perms->get_permissions('view_source') ) |
345 if ( !$this->perms->get_permissions('view_source') ) |
346 { |
346 { |
347 return false; |
347 return false; |
348 } |
348 } |
349 if ( !$this->page_exists ) |
349 if ( !$this->page_exists ) |
350 { |
350 { |
351 return ''; |
351 return ''; |
352 } |
352 } |
353 $cdata = $this->ns->get_cdata(); |
353 $cdata = $this->ns->get_cdata(); |
354 if ( isset($cdata['password']) ) |
354 if ( isset($cdata['password']) ) |
355 { |
355 { |
356 if ( $cdata['password'] != sha1('') && $cdata['password'] !== $this->password && !empty($cdata['password']) ) |
356 if ( $cdata['password'] != sha1('') && $cdata['password'] !== $this->password && !empty($cdata['password']) ) |
357 { |
357 { |
358 return false; |
358 return false; |
359 } |
359 } |
360 } |
360 } |
361 return $this->fetch_text(); |
361 return $this->fetch_text(); |
362 } |
362 } |
363 |
363 |
364 /** |
364 /** |
365 * Updates (saves/changes/edits) the content of the page. |
365 * Updates (saves/changes/edits) the content of the page. |
366 * @param string The new text for the page |
366 * @param string The new text for the page |
367 * @param string A summary of edits made to the page. |
367 * @param string A summary of edits made to the page. |
368 * @param bool If true, the edit is marked as a minor revision |
368 * @param bool If true, the edit is marked as a minor revision |
369 * @param string Page format - wikitext or xhtml. REQUIRED, and new in 1.1.6. |
369 * @param string Page format - wikitext or xhtml. REQUIRED, and new in 1.1.6. |
370 * @return bool True on success, false on failure. When returning false, it will push errors to the PageProcessor error stack; read with $page->pop_error() |
370 * @return bool True on success, false on failure. When returning false, it will push errors to the PageProcessor error stack; read with $page->pop_error() |
371 */ |
371 */ |
372 |
372 |
373 function update_page($text, $edit_summary = false, $minor_edit = false, $page_format) |
373 function update_page($text, $edit_summary = false, $minor_edit = false, $page_format) |
374 { |
374 { |
375 global $db, $session, $paths, $template, $plugins; // Common objects |
375 global $db, $session, $paths, $template, $plugins; // Common objects |
376 global $lang; |
376 global $lang; |
377 |
377 |
378 // Create the page if it doesn't exist |
378 // Create the page if it doesn't exist |
379 if ( !$this->page_exists ) |
379 if ( !$this->page_exists ) |
380 { |
380 { |
381 if ( !$this->create_page() ) |
381 if ( !$this->create_page() ) |
382 { |
382 { |
383 return false; |
383 return false; |
384 } |
384 } |
385 } |
385 } |
386 |
386 |
387 // |
387 // |
388 // Validation |
388 // Validation |
389 // |
389 // |
390 |
390 |
391 $page_id = $db->escape($this->page_id); |
391 $page_id = $db->escape($this->page_id); |
392 $namespace = $db->escape($this->namespace); |
392 $namespace = $db->escape($this->namespace); |
393 |
393 |
394 $q = $db->sql_query('SELECT protected FROM ' . table_prefix . "pages WHERE urlname='$page_id' AND namespace='$namespace';"); |
394 $q = $db->sql_query('SELECT protected FROM ' . table_prefix . "pages WHERE urlname='$page_id' AND namespace='$namespace';"); |
395 if ( !$q ) |
395 if ( !$q ) |
396 $db->_die('PageProcess updating page content'); |
396 $db->_die('PageProcess updating page content'); |
397 if ( $db->numrows() < 1 ) |
397 if ( $db->numrows() < 1 ) |
398 { |
398 { |
399 $this->raise_error($lang->get('editor_err_no_rows')); |
399 $this->raise_error($lang->get('editor_err_no_rows')); |
400 return false; |
400 return false; |
401 } |
401 } |
402 |
402 |
403 // Do we have permission to edit the page? |
403 // Do we have permission to edit the page? |
404 if ( !$this->perms->get_permissions('edit_page') ) |
404 if ( !$this->perms->get_permissions('edit_page') ) |
405 { |
405 { |
406 $this->raise_error($lang->get('editor_err_no_permission')); |
406 $this->raise_error($lang->get('editor_err_no_permission')); |
407 return false; |
407 return false; |
408 } |
408 } |
409 |
409 |
410 list($protection) = $db->fetchrow_num(); |
410 list($protection) = $db->fetchrow_num(); |
411 $db->free_result(); |
411 $db->free_result(); |
412 |
412 |
413 if ( $protection == 1 ) |
413 if ( $protection == 1 ) |
414 { |
414 { |
415 // The page is protected - do we have permission to edit protected pages? |
415 // The page is protected - do we have permission to edit protected pages? |
416 if ( !$this->perms->get_permissions('even_when_protected') ) |
416 if ( !$this->perms->get_permissions('even_when_protected') ) |
417 { |
417 { |
418 $this->raise_error($lang->get('editor_err_page_protected')); |
418 $this->raise_error($lang->get('editor_err_page_protected')); |
419 return false; |
419 return false; |
420 } |
420 } |
421 } |
421 } |
422 else if ( $protection == 2 ) |
422 else if ( $protection == 2 ) |
423 { |
423 { |
424 // The page is semi-protected. |
424 // The page is semi-protected. |
425 if ( |
425 if ( |
426 ( !$session->user_logged_in || // Is the user logged in? |
426 ( !$session->user_logged_in || // Is the user logged in? |
427 ( $session->user_logged_in && $session->reg_time + ( 4 * 86400 ) >= time() ) ) // If so, have they been registered for 4 days? |
427 ( $session->user_logged_in && $session->reg_time + ( 4 * 86400 ) >= time() ) ) // If so, have they been registered for 4 days? |
428 && !$this->perms->get_permissions('even_when_protected') ) // And of course, is there an ACL that overrides semi-protection? |
428 && !$this->perms->get_permissions('even_when_protected') ) // And of course, is there an ACL that overrides semi-protection? |
429 { |
429 { |
430 $this->raise_error($lang->get('editor_err_page_protected')); |
430 $this->raise_error($lang->get('editor_err_page_protected')); |
431 return false; |
431 return false; |
432 } |
432 } |
433 } |
433 } |
434 |
434 |
435 // Spam check |
435 // Spam check |
436 if ( !spamalyze($text) ) |
436 if ( !spamalyze($text) ) |
437 { |
437 { |
438 $this->raise_error($lang->get('editor_err_spamcheck_failed')); |
438 $this->raise_error($lang->get('editor_err_spamcheck_failed')); |
439 return false; |
439 return false; |
440 } |
440 } |
441 |
441 |
442 // Page format check |
442 // Page format check |
443 if ( !in_array($page_format, array('xhtml', 'wikitext')) ) |
443 if ( !in_array($page_format, array('xhtml', 'wikitext')) ) |
444 { |
444 { |
445 $this->raise_error("format \"$page_format\" not one of [xhtml, wikitext]"); |
445 $this->raise_error("format \"$page_format\" not one of [xhtml, wikitext]"); |
446 return false; |
446 return false; |
447 } |
447 } |
448 |
448 |
449 // |
449 // |
450 // Protection validated; update page content |
450 // Protection validated; update page content |
451 // |
451 // |
452 |
452 |
453 $text_undb = RenderMan::preprocess_text($text, false, false); |
453 $text_undb = RenderMan::preprocess_text($text, false, false); |
454 $text = $db->escape($text_undb); |
454 $text = $db->escape($text_undb); |
455 $author = $db->escape($session->username); |
455 $author = $db->escape($session->username); |
456 $time = time(); |
456 $time = time(); |
457 $edit_summary = ( strval($edit_summary) === $edit_summary ) ? $db->escape($edit_summary) : ''; |
457 $edit_summary = ( strval($edit_summary) === $edit_summary ) ? $db->escape($edit_summary) : ''; |
458 $minor_edit = ( $minor_edit ) ? '1' : '0'; |
458 $minor_edit = ( $minor_edit ) ? '1' : '0'; |
459 $date_string = enano_date(ED_DATE | ED_TIME); |
459 $date_string = enano_date(ED_DATE | ED_TIME); |
460 |
460 |
461 // Insert log entry |
461 // Insert log entry |
462 $sql = 'INSERT INTO ' . table_prefix . "logs ( time_id, date_string, log_type, action, page_id, namespace, author, author_uid, page_text, edit_summary, minor_edit, page_format )\n" |
462 $sql = 'INSERT INTO ' . table_prefix . "logs ( time_id, date_string, log_type, action, page_id, namespace, author, author_uid, page_text, edit_summary, minor_edit, page_format )\n" |
463 . " VALUES ( $time, '$date_string', 'page', 'edit', '{$this->page_id}', '{$this->namespace}', '$author', $session->user_id, '$text', '$edit_summary', $minor_edit, '$page_format' );"; |
463 . " VALUES ( $time, '$date_string', 'page', 'edit', '{$this->page_id}', '{$this->namespace}', '$author', $session->user_id, '$text', '$edit_summary', $minor_edit, '$page_format' );"; |
464 if ( !$db->sql_query($sql) ) |
464 if ( !$db->sql_query($sql) ) |
465 { |
465 { |
466 $this->raise_error($db->get_error()); |
466 $this->raise_error($db->get_error()); |
467 return false; |
467 return false; |
468 } |
468 } |
469 |
469 |
470 // Update the master text entry |
470 // Update the master text entry |
471 $sql = 'UPDATE ' . table_prefix . "page_text SET page_text = '$text' WHERE page_id = '{$this->page_id}' AND namespace = '{$this->namespace}';"; |
471 $sql = 'UPDATE ' . table_prefix . "page_text SET page_text = '$text' WHERE page_id = '{$this->page_id}' AND namespace = '{$this->namespace}';"; |
472 if ( !$db->sql_query($sql) ) |
472 if ( !$db->sql_query($sql) ) |
473 { |
473 { |
474 $this->raise_error($db->get_error()); |
474 $this->raise_error($db->get_error()); |
475 return false; |
475 return false; |
476 } |
476 } |
477 |
477 |
478 // If there's an identical draft copy, delete it |
478 // If there's an identical draft copy, delete it |
479 $sql = 'DELETE FROM ' . table_prefix . "logs WHERE is_draft = 1 AND page_id = '{$this->page_id}' AND namespace = '{$this->namespace}' AND page_text = '{$text}';"; |
479 $sql = 'DELETE FROM ' . table_prefix . "logs WHERE is_draft = 1 AND page_id = '{$this->page_id}' AND namespace = '{$this->namespace}' AND page_text = '{$text}';"; |
480 if ( !$db->sql_query($sql) ) |
480 if ( !$db->sql_query($sql) ) |
481 { |
481 { |
482 $this->raise_error($db->get_error()); |
482 $this->raise_error($db->get_error()); |
483 return false; |
483 return false; |
484 } |
484 } |
485 |
485 |
486 // Set page_format |
486 // Set page_format |
487 // Using @ due to warning thrown when saving new page |
487 // Using @ due to warning thrown when saving new page |
488 $cdata = $this->ns->get_cdata(); |
488 $cdata = $this->ns->get_cdata(); |
489 if ( @$cdata['page_format'] !== $page_format ) |
489 if ( @$cdata['page_format'] !== $page_format ) |
490 { |
490 { |
491 // Note: no SQL injection to worry about here. Everything that goes into this is sanitized already, barring some rogue plugin. |
491 // Note: no SQL injection to worry about here. Everything that goes into this is sanitized already, barring some rogue plugin. |
492 // (and if there's a rogue plugin running, we have bigger things to worry about anyway.) |
492 // (and if there's a rogue plugin running, we have bigger things to worry about anyway.) |
493 if ( !$db->sql_query('UPDATE ' . table_prefix . "pages SET page_format = '$page_format' WHERE urlname = '$this->page_id' AND namespace = '$this->namespace';") ) |
493 if ( !$db->sql_query('UPDATE ' . table_prefix . "pages SET page_format = '$page_format' WHERE urlname = '$this->page_id' AND namespace = '$this->namespace';") ) |
494 { |
494 { |
495 $this->raise_error($db->get_error()); |
495 $this->raise_error($db->get_error()); |
496 return false; |
496 return false; |
497 } |
497 } |
498 $paths->update_metadata_cache(); |
498 $paths->update_metadata_cache(); |
499 } |
499 } |
500 |
500 |
501 // Rebuild the search index |
501 // Rebuild the search index |
502 $paths->rebuild_page_index($this->page_id, $this->namespace); |
502 $paths->rebuild_page_index($this->page_id, $this->namespace); |
503 |
503 |
504 $this->text_cache = $text_undb; |
504 $this->text_cache = $text_undb; |
505 |
505 |
506 return true; |
506 return true; |
507 |
507 |
508 } |
508 } |
509 |
509 |
510 /** |
510 /** |
511 * Creates the page if it doesn't already exist. |
511 * Creates the page if it doesn't already exist. |
512 * @param string Optional page title. |
512 * @param string Optional page title. |
513 * @param bool Visibility (allow indexing) flag |
513 * @param bool Visibility (allow indexing) flag |
514 * @return bool True on success, false on failure. |
514 * @return bool True on success, false on failure. |
515 */ |
515 */ |
516 |
516 |
517 function create_page($title = false, $visible = true) |
517 function create_page($title = false, $visible = true) |
518 { |
518 { |
519 global $db, $session, $paths, $template, $plugins; // Common objects |
519 global $db, $session, $paths, $template, $plugins; // Common objects |
520 global $lang; |
520 global $lang; |
521 |
521 |
522 // Do we have permission to create the page? |
522 // Do we have permission to create the page? |
523 if ( !$this->perms->get_permissions('create_page') ) |
523 if ( !$this->perms->get_permissions('create_page') ) |
524 { |
524 { |
525 $this->raise_error($lang->get('pagetools_create_err_no_permission')); |
525 $this->raise_error($lang->get('pagetools_create_err_no_permission')); |
526 return false; |
526 return false; |
527 } |
527 } |
528 |
528 |
529 // Does it already exist? |
529 // Does it already exist? |
530 if ( $this->page_exists ) |
530 if ( $this->page_exists ) |
531 { |
531 { |
532 $this->raise_error($lang->get('pagetools_create_err_already_exists')); |
532 $this->raise_error($lang->get('pagetools_create_err_already_exists')); |
533 return false; |
533 return false; |
534 } |
534 } |
535 |
535 |
536 // It's not in there. Perform validation. |
536 // It's not in there. Perform validation. |
537 |
537 |
538 // We can't create special, admin, or external pages. |
538 // We can't create special, admin, or external pages. |
539 if ( $this->namespace == 'Special' || $this->namespace == 'Admin' || $this->namespace == 'API' ) |
539 if ( $this->namespace == 'Special' || $this->namespace == 'Admin' || $this->namespace == 'API' ) |
540 { |
540 { |
541 $this->raise_error($lang->get('pagetools_create_err_nodb_namespace')); |
541 $this->raise_error($lang->get('pagetools_create_err_nodb_namespace')); |
542 return false; |
542 return false; |
543 } |
543 } |
544 |
544 |
545 // Guess the proper title |
545 // Guess the proper title |
546 $name = ( !empty($title) ) ? $title : str_replace('_', ' ', dirtify_page_id($this->page_id)); |
546 $name = ( !empty($title) ) ? $title : str_replace('_', ' ', dirtify_page_id($this->page_id)); |
547 |
547 |
548 // Check for the restricted Project: prefix |
548 // Check for the restricted Project: prefix |
549 if ( substr($this->page_id, 0, 8) == 'Project:' ) |
549 if ( substr($this->page_id, 0, 8) == 'Project:' ) |
550 { |
550 { |
551 $this->raise_error($lang->get('pagetools_create_err_reserved_prefix')); |
551 $this->raise_error($lang->get('pagetools_create_err_reserved_prefix')); |
552 return false; |
552 return false; |
553 } |
553 } |
554 |
554 |
555 // Validation successful - insert the page |
555 // Validation successful - insert the page |
556 |
556 |
557 $metadata = array( |
557 $metadata = array( |
558 'urlname' => $this->page_id, |
558 'urlname' => $this->page_id, |
559 'namespace' => $this->namespace, |
559 'namespace' => $this->namespace, |
560 'name' => $name, |
560 'name' => $name, |
561 'special' => 0, |
561 'special' => 0, |
562 'visible' => $visible ? 1 : 0, |
562 'visible' => $visible ? 1 : 0, |
563 'comments_on' => 1, |
563 'comments_on' => 1, |
564 'protected' => ( $this->namespace == 'System' ? 1 : 0 ), |
564 'protected' => ( $this->namespace == 'System' ? 1 : 0 ), |
565 'delvotes' => 0, |
565 'delvotes' => 0, |
566 'delvote_ips' => serialize(array()), |
566 'delvote_ips' => serialize(array()), |
567 'wiki_mode' => 2 |
567 'wiki_mode' => 2 |
568 ); |
568 ); |
569 |
569 |
570 $paths->add_page($metadata); |
570 $paths->add_page($metadata); |
571 |
571 |
572 $page_id = $db->escape($this->page_id); |
572 $page_id = $db->escape($this->page_id); |
573 $namespace = $db->escape($this->namespace); |
573 $namespace = $db->escape($this->namespace); |
574 $name = $db->escape($name); |
574 $name = $db->escape($name); |
575 $protect = ( $this->namespace == 'System' ) ? '1' : '0'; |
575 $protect = ( $this->namespace == 'System' ) ? '1' : '0'; |
576 $blank_array = $db->escape(serialize(array())); |
576 $blank_array = $db->escape(serialize(array())); |
577 |
577 |
578 // Query 1: Metadata entry |
578 // Query 1: Metadata entry |
579 $q = $db->sql_query('INSERT INTO ' . table_prefix . "pages(name, urlname, namespace, visible, protected, delvotes, delvote_ips, wiki_mode)\n" |
579 $q = $db->sql_query('INSERT INTO ' . table_prefix . "pages(name, urlname, namespace, visible, protected, delvotes, delvote_ips, wiki_mode)\n" |
580 . " VALUES ( '$name', '$page_id', '$namespace', {$metadata['visible']}, $protect, 0, '$blank_array', 2 );"); |
580 . " VALUES ( '$name', '$page_id', '$namespace', {$metadata['visible']}, $protect, 0, '$blank_array', 2 );"); |
581 if ( !$q ) |
581 if ( !$q ) |
582 $db->_die('PageProcessor page creation - metadata stage'); |
582 $db->_die('PageProcessor page creation - metadata stage'); |
583 |
583 |
584 // Query 2: Text insertion |
584 // Query 2: Text insertion |
585 $q = $db->sql_query('INSERT INTO ' . table_prefix . "page_text(page_id, namespace, page_text)\n" |
585 $q = $db->sql_query('INSERT INTO ' . table_prefix . "page_text(page_id, namespace, page_text)\n" |
586 . "VALUES ( '$page_id', '$namespace', '' );"); |
586 . "VALUES ( '$page_id', '$namespace', '' );"); |
587 if ( !$q ) |
587 if ( !$q ) |
588 $db->_die('PageProcessor page creation - text stage'); |
588 $db->_die('PageProcessor page creation - text stage'); |
589 |
589 |
590 // Query 3: Log entry |
590 // Query 3: Log entry |
591 $db->sql_query('INSERT INTO ' . table_prefix."logs(time_id, date_string, log_type, action, author, author_uid, page_id, namespace)\n" |
591 $db->sql_query('INSERT INTO ' . table_prefix."logs(time_id, date_string, log_type, action, author, author_uid, page_id, namespace)\n" |
592 . " VALUES ( " . time() . ", 'DEPRECATED', 'page', 'create', \n" |
592 . " VALUES ( " . time() . ", 'DEPRECATED', 'page', 'create', \n" |
593 . " '" . $db->escape($session->username) . "', $session->user_id, '" . $db->escape($this->page_id) . "', '" . $this->namespace . "');"); |
593 . " '" . $db->escape($session->username) . "', $session->user_id, '" . $db->escape($this->page_id) . "', '" . $this->namespace . "');"); |
594 if ( !$q ) |
594 if ( !$q ) |
595 $db->_die('PageProcessor page creation - logging stage'); |
595 $db->_die('PageProcessor page creation - logging stage'); |
596 |
596 |
597 // Update the cache |
597 // Update the cache |
598 $paths->update_metadata_cache(); |
598 $paths->update_metadata_cache(); |
599 |
599 |
600 // Make sure that when/if we save the page later in this instance it doesn't get re-created |
600 // Make sure that when/if we save the page later in this instance it doesn't get re-created |
601 $this->page_exists = true; |
601 $this->page_exists = true; |
602 |
602 |
603 // Page created. We're good! |
603 // Page created. We're good! |
604 return true; |
604 return true; |
605 } |
605 } |
606 |
606 |
607 /** |
607 /** |
608 * Rolls back a non-edit action in the logs |
608 * Rolls back a non-edit action in the logs |
609 * @param int Log entry (log_id) to roll back |
609 * @param int Log entry (log_id) to roll back |
610 * @return array Standard Enano error/success protocol |
610 * @return array Standard Enano error/success protocol |
611 */ |
611 */ |
612 |
612 |
613 function rollback_log_entry($log_id) |
613 function rollback_log_entry($log_id) |
614 { |
614 { |
615 global $db, $session, $paths, $template, $plugins; // Common objects |
615 global $db, $session, $paths, $template, $plugins; // Common objects |
616 global $cache; |
616 global $cache; |
617 |
617 |
618 // Verify permissions |
618 // Verify permissions |
619 if ( !$this->perms->get_permissions('history_rollback') ) |
619 if ( !$this->perms->get_permissions('history_rollback') ) |
620 { |
620 { |
621 return array( |
621 return array( |
622 'success' => false, |
622 'success' => false, |
623 'error' => 'access_denied' |
623 'error' => 'access_denied' |
624 ); |
624 ); |
625 } |
625 } |
626 |
626 |
627 // Check input |
627 // Check input |
628 $log_id = intval($log_id); |
628 $log_id = intval($log_id); |
629 if ( empty($log_id) ) |
629 if ( empty($log_id) ) |
630 { |
630 { |
631 return array( |
631 return array( |
632 'success' => false, |
632 'success' => false, |
633 'error' => 'invalid_parameter' |
633 'error' => 'invalid_parameter' |
634 ); |
634 ); |
635 } |
635 } |
636 |
636 |
637 // Fetch the log entry |
637 // Fetch the log entry |
638 $q = $db->sql_query('SELECT * FROM ' . table_prefix . "logs WHERE log_type = 'page' AND page_id='{$this->page_id}' AND namespace='{$this->namespace}' AND log_id = $log_id;"); |
638 $q = $db->sql_query('SELECT * FROM ' . table_prefix . "logs WHERE log_type = 'page' AND page_id='{$this->page_id}' AND namespace='{$this->namespace}' AND log_id = $log_id;"); |
639 if ( !$q ) |
639 if ( !$q ) |
640 $db->_die(); |
640 $db->_die(); |
641 |
641 |
642 // Is this even a valid log entry for this context? |
642 // Is this even a valid log entry for this context? |
643 if ( $db->numrows() < 1 ) |
643 if ( $db->numrows() < 1 ) |
644 { |
644 { |
645 return array( |
645 return array( |
646 'success' => false, |
646 'success' => false, |
647 'error' => 'entry_not_found' |
647 'error' => 'entry_not_found' |
648 ); |
648 ); |
649 } |
649 } |
650 |
650 |
651 // All good, fetch and free the result |
651 // All good, fetch and free the result |
652 $log_entry = $db->fetchrow(); |
652 $log_entry = $db->fetchrow(); |
653 $db->free_result(); |
653 $db->free_result(); |
654 |
654 |
655 $dateline = enano_date(ED_DATE | ED_TIME, $log_entry['time_id']); |
655 $dateline = enano_date(ED_DATE | ED_TIME, $log_entry['time_id']); |
656 |
656 |
657 // Let's see, what do we have here... |
657 // Let's see, what do we have here... |
658 switch ( $log_entry['action'] ) |
658 switch ( $log_entry['action'] ) |
659 { |
659 { |
660 case 'rename': |
660 case 'rename': |
661 // Page was renamed, let the rename method handle this |
661 // Page was renamed, let the rename method handle this |
662 return array_merge($this->rename_page($log_entry['edit_summary']), array('dateline' => $dateline, 'action' => $log_entry['action'])); |
662 return array_merge($this->rename_page($log_entry['edit_summary']), array('dateline' => $dateline, 'action' => $log_entry['action'])); |
663 break; |
663 break; |
664 case 'prot': |
664 case 'prot': |
665 case 'unprot': |
665 case 'unprot': |
666 case 'semiprot': |
666 case 'semiprot': |
667 return array_merge($this->protect_page(intval($log_entry['page_text']), '__REVERSION__'), array('dateline' => $dateline, 'action' => $log_entry['action'])); |
667 return array_merge($this->protect_page(intval($log_entry['page_text']), '__REVERSION__'), array('dateline' => $dateline, 'action' => $log_entry['action'])); |
668 break; |
668 break; |
669 case 'delete': |
669 case 'delete': |
670 |
670 |
671 // Raising a previously dead page has implications... |
671 // Raising a previously dead page has implications... |
672 |
672 |
673 // FIXME: l10n |
673 // FIXME: l10n |
674 // rollback_extra is required because usually only moderators can undo page deletion AND restore the content. |
674 // rollback_extra is required because usually only moderators can undo page deletion AND restore the content. |
675 // potential flaw here - once recreated, can past revisions be restored by users without rollback_extra? should |
675 // potential flaw here - once recreated, can past revisions be restored by users without rollback_extra? should |
676 // probably modify editor routine to deny revert access if the timestamp < timestamp of last deletion if any. |
676 // probably modify editor routine to deny revert access if the timestamp < timestamp of last deletion if any. |
677 if ( !$this->perms->get_permissions('history_rollback_extra') ) |
677 if ( !$this->perms->get_permissions('history_rollback_extra') ) |
678 return 'Administrative privileges are required for page undeletion.'; |
678 return 'Administrative privileges are required for page undeletion.'; |
679 |
679 |
680 // Rolling back the deletion of a page that was since created? |
680 // Rolling back the deletion of a page that was since created? |
681 $pathskey = $paths->nslist[ $this->namespace ] . $this->page_id; |
681 $pathskey = $paths->nslist[ $this->namespace ] . $this->page_id; |
682 if ( isPage($pathskey) ) |
682 if ( isPage($pathskey) ) |
683 return array( |
683 return array( |
684 'success' => false, |
684 'success' => false, |
685 // This is a clean Christian in-joke. |
685 // This is a clean Christian in-joke. |
686 'error' => 'seeking_living_among_dead' |
686 'error' => 'seeking_living_among_dead' |
687 ); |
687 ); |
688 |
688 |
689 // Generate a crappy page name |
689 // Generate a crappy page name |
690 $name = $db->escape( str_replace('_', ' ', dirtify_page_id($this->page_id)) ); |
690 $name = $db->escape( str_replace('_', ' ', dirtify_page_id($this->page_id)) ); |
691 |
691 |
692 // Stage 1 - re-insert page |
692 // Stage 1 - re-insert page |
693 $e = $db->sql_query('INSERT INTO ' . table_prefix.'pages(name,urlname,namespace) VALUES( \'' . $name . '\', \'' . $this->page_id . '\',\'' . $this->namespace . '\' )'); |
693 $e = $db->sql_query('INSERT INTO ' . table_prefix.'pages(name,urlname,namespace) VALUES( \'' . $name . '\', \'' . $this->page_id . '\',\'' . $this->namespace . '\' )'); |
694 if ( !$e ) |
694 if ( !$e ) |
695 $db->die_json(); |
695 $db->die_json(); |
696 |
696 |
697 // Select the latest published revision |
697 // Select the latest published revision |
698 $q = $db->sql_query('SELECT page_text FROM ' . table_prefix . "logs WHERE\n" |
698 $q = $db->sql_query('SELECT page_text FROM ' . table_prefix . "logs WHERE\n" |
699 . " log_type = 'page'\n" |
699 . " log_type = 'page'\n" |
700 . " AND action = 'edit'\n" |
700 . " AND action = 'edit'\n" |
701 . " AND page_id = '$this->page_id'\n" |
701 . " AND page_id = '$this->page_id'\n" |
702 . " AND namespace = '$this->namespace'\n" |
702 . " AND namespace = '$this->namespace'\n" |
703 . " AND is_draft != 1\n" |
703 . " AND is_draft != 1\n" |
704 . "ORDER BY time_id DESC LIMIT 1;"); |
704 . "ORDER BY time_id DESC LIMIT 1;"); |
705 if ( !$q ) |
705 if ( !$q ) |
706 $db->die_json(); |
706 $db->die_json(); |
707 list($page_text) = $db->fetchrow_num(); |
707 list($page_text) = $db->fetchrow_num(); |
708 $db->free_result($q); |
708 $db->free_result($q); |
709 |
709 |
710 // Apply the latest revision as the current page text |
710 // Apply the latest revision as the current page text |
711 $page_text = $db->escape($page_text); |
711 $page_text = $db->escape($page_text); |
712 $e = $db->sql_query('INSERT INTO ' . table_prefix."page_text(page_id, namespace, page_text) VALUES\n" |
712 $e = $db->sql_query('INSERT INTO ' . table_prefix."page_text(page_id, namespace, page_text) VALUES\n" |
713 . " ( '$this->page_id', '$this->namespace', '$page_text' );"); |
713 . " ( '$this->page_id', '$this->namespace', '$page_text' );"); |
714 if ( !$e ) |
714 if ( !$e ) |
715 $db->die_json(); |
715 $db->die_json(); |
716 |
716 |
717 $cache->purge('page_meta'); |
717 $cache->purge('page_meta'); |
718 |
718 |
719 return array( |
719 return array( |
720 'success' => true, |
720 'success' => true, |
721 'dateline' => $dateline, |
721 'dateline' => $dateline, |
722 'action' => $log_entry['action'] |
722 'action' => $log_entry['action'] |
723 ); |
723 ); |
724 |
724 |
725 break; |
725 break; |
726 case 'reupload': |
726 case 'reupload': |
727 |
727 |
728 // given a log id and some revision info, restore the old file. |
728 // given a log id and some revision info, restore the old file. |
729 // get the timestamp of the file before this one |
729 // get the timestamp of the file before this one |
730 $q = $db->sql_query('SELECT time_id, file_key, file_extension, filename, size, mimetype FROM ' . table_prefix . "files WHERE time_id < {$log_entry['time_id']} ORDER BY time_id DESC LIMIT 1;"); |
730 $q = $db->sql_query('SELECT time_id, file_key, file_extension, filename, size, mimetype FROM ' . table_prefix . "files WHERE time_id < {$log_entry['time_id']} ORDER BY time_id DESC LIMIT 1;"); |
731 if ( !$q ) |
731 if ( !$q ) |
732 $db->_die(); |
732 $db->_die(); |
733 |
733 |
734 $row = $db->fetchrow(); |
734 $row = $db->fetchrow(); |
735 $db->free_result(); |
735 $db->free_result(); |
736 |
736 |
737 // If the file hasn't been renamed to the new format (omitting timestamp), do that now. |
737 // If the file hasn't been renamed to the new format (omitting timestamp), do that now. |
738 $fname = ENANO_ROOT . "/files/{$row['file_key']}_{$row['time_id']}{$row['file_extension']}"; |
738 $fname = ENANO_ROOT . "/files/{$row['file_key']}_{$row['time_id']}{$row['file_extension']}"; |
739 if ( @file_exists($fname) ) |
739 if ( @file_exists($fname) ) |
740 { |
740 { |
741 // it's stored in the old format - rename |
741 // it's stored in the old format - rename |
742 $fname_new = ENANO_ROOT . "/files/{$row['file_key']}{$row['file_extension']}"; |
742 $fname_new = ENANO_ROOT . "/files/{$row['file_key']}{$row['file_extension']}"; |
743 if ( !@rename($fname, $fname_new) ) |
743 if ( !@rename($fname, $fname_new) ) |
744 { |
744 { |
745 return array( |
745 return array( |
746 'success' => false, |
746 'success' => false, |
747 'error' => 'rb_file_rename_failed', |
747 'error' => 'rb_file_rename_failed', |
748 'action' => $log_entry['action'] |
748 'action' => $log_entry['action'] |
749 ); |
749 ); |
750 } |
750 } |
751 } |
751 } |
752 |
752 |
753 // Insert a new file entry |
753 // Insert a new file entry |
754 $time = time(); |
754 $time = time(); |
755 $filename = $db->escape($row['filename']); |
755 $filename = $db->escape($row['filename']); |
756 $mimetype = $db->escape($row['mimetype']); |
756 $mimetype = $db->escape($row['mimetype']); |
757 $ext = $db->escape($row['file_extension']); |
757 $ext = $db->escape($row['file_extension']); |
758 $key = $db->escape($row['file_key']); |
758 $key = $db->escape($row['file_key']); |
759 |
759 |
760 $q = $db->sql_query('INSERT INTO ' . table_prefix . "files ( time_id, page_id, filename, size, mimetype, file_extension, file_key ) VALUES\n" |
760 $q = $db->sql_query('INSERT INTO ' . table_prefix . "files ( time_id, page_id, filename, size, mimetype, file_extension, file_key ) VALUES\n" |
761 . " ( $time, '$this->page_id', '$filename', {$row['size']}, '$mimetype', '$ext', '$key' );"); |
761 . " ( $time, '$this->page_id', '$filename', {$row['size']}, '$mimetype', '$ext', '$key' );"); |
762 if ( !$q ) |
762 if ( !$q ) |
763 $db->die_json(); |
763 $db->die_json(); |
764 |
764 |
765 // add reupload log entry |
765 // add reupload log entry |
766 $username = $db->escape($session->username); |
766 $username = $db->escape($session->username); |
767 $q = $db->sql_query('INSERT INTO ' . table_prefix . "logs ( log_type, action, time_id, page_id, namespace, author, author_uid, edit_summary ) VALUES\n" |
767 $q = $db->sql_query('INSERT INTO ' . table_prefix . "logs ( log_type, action, time_id, page_id, namespace, author, author_uid, edit_summary ) VALUES\n" |
768 . " ( 'page', 'reupload', $time, '$this->page_id', '$this->namespace', '$username', $session->user_id, '__ROLLBACK__' )"); |
768 . " ( 'page', 'reupload', $time, '$this->page_id', '$this->namespace', '$username', $session->user_id, '__ROLLBACK__' )"); |
769 if ( !$q ) |
769 if ( !$q ) |
770 $db->die_json(); |
770 $db->die_json(); |
771 |
771 |
772 return array( |
772 return array( |
773 'success' => true, |
773 'success' => true, |
774 'dateline' => $dateline, |
774 'dateline' => $dateline, |
775 'action' => $log_entry['action'] |
775 'action' => $log_entry['action'] |
776 ); |
776 ); |
777 |
777 |
778 break; |
778 break; |
779 case 'votereset': |
779 case 'votereset': |
780 if ( !$this->perms->get_permissions('history_rollback_extra') ) |
780 if ( !$this->perms->get_permissions('history_rollback_extra') ) |
781 return 'Denied!'; |
781 return 'Denied!'; |
782 |
782 |
783 // pull existing vote data |
783 // pull existing vote data |
784 $q = $db->sql_query('SELECT delvotes, delvote_ips FROM ' . table_prefix . "pages WHERE urlname = '$this->page_id' AND namespace = '$this->namespace';"); |
784 $q = $db->sql_query('SELECT delvotes, delvote_ips FROM ' . table_prefix . "pages WHERE urlname = '$this->page_id' AND namespace = '$this->namespace';"); |
785 if ( !$q ) |
785 if ( !$q ) |
786 $db->_die(); |
786 $db->_die(); |
787 |
787 |
788 if ( $db->numrows() < 1 ) |
788 if ( $db->numrows() < 1 ) |
789 return array( |
789 return array( |
790 'success' => false, |
790 'success' => false, |
791 'error' => 'page_not_exist', |
791 'error' => 'page_not_exist', |
792 'action' => $log_entry['action'] |
792 'action' => $log_entry['action'] |
793 ); |
793 ); |
794 |
794 |
795 list($curr_delvotes, $curr_delvote_ips) = $db->fetchrow_num(); |
795 list($curr_delvotes, $curr_delvote_ips) = $db->fetchrow_num(); |
796 $db->free_result(); |
796 $db->free_result(); |
797 |
797 |
798 // merge with existing votes |
798 // merge with existing votes |
799 $old_delvote_ips = unserialize($log_entry['page_text']); |
799 $old_delvote_ips = unserialize($log_entry['page_text']); |
800 $new_delvote_ips = unserialize($curr_delvote_ips); |
800 $new_delvote_ips = unserialize($curr_delvote_ips); |
801 $new_delvote_ips['u'] = array_unique(array_merge($new_delvote_ips['u'], $old_delvote_ips['u'])); |
801 $new_delvote_ips['u'] = array_unique(array_merge($new_delvote_ips['u'], $old_delvote_ips['u'])); |
802 $new_delvote_ips['ip'] = array_unique(array_merge($new_delvote_ips['ip'], $old_delvote_ips['ip'])); |
802 $new_delvote_ips['ip'] = array_unique(array_merge($new_delvote_ips['ip'], $old_delvote_ips['ip'])); |
803 $new_delvotes = count($new_delvote_ips['ip']); |
803 $new_delvotes = count($new_delvote_ips['ip']); |
804 $new_delvote_ips = $db->escape(serialize($new_delvote_ips)); |
804 $new_delvote_ips = $db->escape(serialize($new_delvote_ips)); |
805 |
805 |
806 // update pages table |
806 // update pages table |
807 $q = $db->sql_query('UPDATE ' . table_prefix . "pages SET delvotes = $new_delvotes, delvote_ips = '$new_delvote_ips' WHERE urlname = '$this->page_id' AND namespace = '$this->namespace';"); |
807 $q = $db->sql_query('UPDATE ' . table_prefix . "pages SET delvotes = $new_delvotes, delvote_ips = '$new_delvote_ips' WHERE urlname = '$this->page_id' AND namespace = '$this->namespace';"); |
808 |
808 |
809 $cache->purge('page_meta'); |
809 $cache->purge('page_meta'); |
810 |
810 |
811 return array( |
811 return array( |
812 'success' => true, |
812 'success' => true, |
813 'dateline' => $dateline, |
813 'dateline' => $dateline, |
814 'action' => $log_entry['action'] |
814 'action' => $log_entry['action'] |
815 ); |
815 ); |
816 break; |
816 break; |
817 default: |
817 default: |
818 |
818 |
819 return array( |
819 return array( |
820 'success' => false, |
820 'success' => false, |
821 'error' => 'rb_action_not_supported', |
821 'error' => 'rb_action_not_supported', |
822 'action' => $log_entry['action'] |
822 'action' => $log_entry['action'] |
823 ); |
823 ); |
824 |
824 |
825 break; |
825 break; |
826 } |
826 } |
827 } |
827 } |
828 |
828 |
829 /** |
829 /** |
830 * Renames the page |
830 * Renames the page |
831 * @param string New name |
831 * @param string New name |
832 * @return array Standard Enano error/success protocol |
832 * @return array Standard Enano error/success protocol |
833 */ |
833 */ |
834 |
834 |
835 function rename_page($new_name) |
835 function rename_page($new_name) |
836 { |
836 { |
837 global $db, $session, $paths, $template, $plugins; // Common objects |
837 global $db, $session, $paths, $template, $plugins; // Common objects |
838 |
838 |
839 // Check permissions |
839 // Check permissions |
840 if ( !$this->perms->get_permissions('rename') ) |
840 if ( !$this->perms->get_permissions('rename') ) |
841 { |
841 { |
842 return array( |
842 return array( |
843 'success' => false, |
843 'success' => false, |
844 'error' => 'access_denied' |
844 'error' => 'access_denied' |
845 ); |
845 ); |
846 } |
846 } |
847 |
847 |
848 // If this is the same as the current name, return success |
848 // If this is the same as the current name, return success |
849 $page_name = get_page_title_ns($this->page_id, $this->namespace); |
849 $page_name = get_page_title_ns($this->page_id, $this->namespace); |
850 if ( $page_name === $new_name ) |
850 if ( $page_name === $new_name ) |
851 { |
851 { |
852 return array( |
852 return array( |
853 'success' => true |
853 'success' => true |
854 ); |
854 ); |
855 } |
855 } |
856 |
856 |
857 // Make sure the name is valid |
857 // Make sure the name is valid |
858 $new_name = trim($new_name); |
858 $new_name = trim($new_name); |
859 if ( empty($new_name) ) |
859 if ( empty($new_name) ) |
860 { |
860 { |
861 return array( |
861 return array( |
862 'success' => false, |
862 'success' => false, |
863 'error' => 'invalid_parameter' |
863 'error' => 'invalid_parameter' |
864 ); |
864 ); |
865 } |
865 } |
866 |
866 |
867 // Log the action |
867 // Log the action |
868 $username = $db->escape($session->username); |
868 $username = $db->escape($session->username); |
869 $page_name = $db->escape($page_name); |
869 $page_name = $db->escape($page_name); |
870 $time = time(); |
870 $time = time(); |
871 |
871 |
872 $q = $db->sql_query('INSERT INTO ' . table_prefix . "logs ( log_type, action, page_id, namespace, author, author_uid, edit_summary, time_id, date_string ) VALUES\n" |
872 $q = $db->sql_query('INSERT INTO ' . table_prefix . "logs ( log_type, action, page_id, namespace, author, author_uid, edit_summary, time_id, date_string ) VALUES\n" |
873 . " ( 'page', 'rename', '{$this->page_id}', '{$this->namespace}', '$username', $session->user_id, '$page_name', '$time', 'DATE_STRING COLUMN OBSOLETE, USE time_id' );"); |
873 . " ( 'page', 'rename', '{$this->page_id}', '{$this->namespace}', '$username', $session->user_id, '$page_name', '$time', 'DATE_STRING COLUMN OBSOLETE, USE time_id' );"); |
874 if ( !$q ) |
874 if ( !$q ) |
875 $db->_die(); |
875 $db->_die(); |
876 |
876 |
877 // Not much to do but to rename it now |
877 // Not much to do but to rename it now |
878 $new_name = $db->escape($new_name); |
878 $new_name = $db->escape($new_name); |
879 $q = $db->sql_query('UPDATE ' . table_prefix . "pages SET name = '$new_name' WHERE urlname = '{$this->page_id}' AND namespace = '{$this->namespace}';"); |
879 $q = $db->sql_query('UPDATE ' . table_prefix . "pages SET name = '$new_name' WHERE urlname = '{$this->page_id}' AND namespace = '{$this->namespace}';"); |
880 if ( !$q ) |
880 if ( !$q ) |
881 $db->_die(); |
881 $db->_die(); |
882 |
882 |
883 // Update the cache |
883 // Update the cache |
884 $paths->update_metadata_cache(); |
884 $paths->update_metadata_cache(); |
885 |
885 |
886 return array( |
886 return array( |
887 'success' => true |
887 'success' => true |
888 ); |
888 ); |
889 } |
889 } |
890 |
890 |
891 /** |
891 /** |
892 * Sets the protection level of the page |
892 * Sets the protection level of the page |
893 * @param int Protection level, one of PROTECT_{FULL,SEMI,NONE} |
893 * @param int Protection level, one of PROTECT_{FULL,SEMI,NONE} |
894 * @param string Reason for protection - required |
894 * @param string Reason for protection - required |
895 */ |
895 */ |
896 |
896 |
897 function protect_page($protection_level, $reason) |
897 function protect_page($protection_level, $reason) |
898 { |
898 { |
899 global $db, $session, $paths, $template, $plugins; // Common objects |
899 global $db, $session, $paths, $template, $plugins; // Common objects |
900 global $cache; |
900 global $cache; |
901 |
901 |
902 // Validate permissions |
902 // Validate permissions |
903 if ( !$this->perms->get_permissions('protect') ) |
903 if ( !$this->perms->get_permissions('protect') ) |
904 { |
904 { |
905 return array( |
905 return array( |
906 'success' => false, |
906 'success' => false, |
907 'error' => 'access_denied' |
907 'error' => 'access_denied' |
908 ); |
908 ); |
909 } |
909 } |
910 |
910 |
911 // Validate re-auth |
911 // Validate re-auth |
912 if ( !$session->sid_super ) |
912 if ( !$session->sid_super ) |
913 { |
913 { |
914 return array( |
914 return array( |
915 'success' => false, |
915 'success' => false, |
916 'error' => 'access_denied_need_reauth' |
916 'error' => 'access_denied_need_reauth' |
917 ); |
917 ); |
918 } |
918 } |
919 |
919 |
920 // Validate input |
920 // Validate input |
921 $reason = trim($reason); |
921 $reason = trim($reason); |
922 if ( !in_array($protection_level, array(PROTECT_NONE, PROTECT_FULL, PROTECT_SEMI)) || empty($reason) ) |
922 if ( !in_array($protection_level, array(PROTECT_NONE, PROTECT_FULL, PROTECT_SEMI)) || empty($reason) ) |
923 { |
923 { |
924 return array( |
924 return array( |
925 'success' => false, |
925 'success' => false, |
926 'error' => 'invalid_parameter' |
926 'error' => 'invalid_parameter' |
927 ); |
927 ); |
928 } |
928 } |
929 |
929 |
930 // Retrieve page metadata |
930 // Retrieve page metadata |
931 $metadata = $this->ns->get_cdata(); |
931 $metadata = $this->ns->get_cdata(); |
932 |
932 |
933 // Log the action |
933 // Log the action |
934 $username = $db->escape($session->username); |
934 $username = $db->escape($session->username); |
935 $time = time(); |
935 $time = time(); |
936 $existing_protection = intval($metadata['protected']); |
936 $existing_protection = intval($metadata['protected']); |
937 $reason = $db->escape($reason); |
937 $reason = $db->escape($reason); |
938 |
938 |
939 if ( $existing_protection == $protection_level ) |
939 if ( $existing_protection == $protection_level ) |
940 { |
940 { |
941 return array( |
941 return array( |
942 'success' => false, |
942 'success' => false, |
943 'error' => 'protection_already_there' |
943 'error' => 'protection_already_there' |
944 ); |
944 ); |
945 } |
945 } |
946 |
946 |
947 $action = '[ insanity ]'; |
947 $action = '[ insanity ]'; |
948 switch($protection_level) |
948 switch($protection_level) |
949 { |
949 { |
950 case PROTECT_FULL: $action = 'prot'; break; |
950 case PROTECT_FULL: $action = 'prot'; break; |
951 case PROTECT_NONE: $action = 'unprot'; break; |
951 case PROTECT_NONE: $action = 'unprot'; break; |
952 case PROTECT_SEMI: $action = 'semiprot'; break; |
952 case PROTECT_SEMI: $action = 'semiprot'; break; |
953 } |
953 } |
954 |
954 |
955 $sql = 'INSERT INTO ' . table_prefix . "logs ( log_type, action, page_id, namespace, author, author_uid, edit_summary, time_id, page_text, date_string ) VALUES\n" |
955 $sql = 'INSERT INTO ' . table_prefix . "logs ( log_type, action, page_id, namespace, author, author_uid, edit_summary, time_id, page_text, date_string ) VALUES\n" |
956 . " ( 'page', '$action', '{$this->page_id}', '{$this->namespace}', '$username', $author_uid, '$reason', '$time', '$existing_protection', 'DATE_STRING COLUMN OBSOLETE, USE time_id' );"; |
956 . " ( 'page', '$action', '{$this->page_id}', '{$this->namespace}', '$username', $author_uid, '$reason', '$time', '$existing_protection', 'DATE_STRING COLUMN OBSOLETE, USE time_id' );"; |
957 if ( !$db->sql_query($sql) ) |
957 if ( !$db->sql_query($sql) ) |
958 { |
958 { |
959 $db->die_json(); |
959 $db->die_json(); |
960 } |
960 } |
961 |
961 |
962 // Perform the actual protection |
962 // Perform the actual protection |
963 $q = $db->sql_query('UPDATE ' . table_prefix . "pages SET protected = $protection_level WHERE urlname = '{$this->page_id}' AND namespace = '{$this->namespace}';"); |
963 $q = $db->sql_query('UPDATE ' . table_prefix . "pages SET protected = $protection_level WHERE urlname = '{$this->page_id}' AND namespace = '{$this->namespace}';"); |
964 if ( !$q ) |
964 if ( !$q ) |
965 $db->die_json(); |
965 $db->die_json(); |
966 |
966 |
967 $cache->purge('page_meta'); |
967 $cache->purge('page_meta'); |
968 |
968 |
969 return array( |
969 return array( |
970 'success' => true |
970 'success' => true |
971 ); |
971 ); |
972 } |
972 } |
973 |
973 |
974 /** |
974 /** |
975 * Sets internal variables. |
975 * Sets internal variables. |
976 * @access private |
976 * @access private |
977 */ |
977 */ |
978 |
978 |
979 function _setup($page_id, $namespace, $revision_id) |
979 function _setup($page_id, $namespace, $revision_id) |
980 { |
980 { |
981 global $db, $session, $paths, $template, $plugins; // Common objects |
981 global $db, $session, $paths, $template, $plugins; // Common objects |
982 |
982 |
983 $page_id_cleaned = sanitize_page_id($page_id); |
983 $page_id_cleaned = sanitize_page_id($page_id); |
984 |
984 |
985 $this->revision_id = $revision_id; |
985 $this->revision_id = $revision_id; |
986 $this->page_id_unclean = dirtify_page_id($page_id); |
986 $this->page_id_unclean = dirtify_page_id($page_id); |
987 |
987 |
988 // resolve namespace |
988 // resolve namespace |
989 $this->ns = namespace_factory($page_id, $namespace, $this->revision_id); |
989 $this->ns = namespace_factory($page_id, $namespace, $this->revision_id); |
990 $this->page_id =& $this->ns->page_id; |
990 $this->page_id =& $this->ns->page_id; |
991 $this->namespace =& $this->ns->namespace; |
991 $this->namespace =& $this->ns->namespace; |
992 |
992 |
993 $this->perms = $session->fetch_page_acl( $page_id, $namespace ); |
993 $this->perms = $session->fetch_page_acl( $page_id, $namespace ); |
994 |
994 |
995 $this->page_exists = $this->ns->exists(); |
995 $this->page_exists = $this->ns->exists(); |
996 $this->title = get_page_title_ns($this->page_id, $this->namespace); |
996 $this->title = get_page_title_ns($this->page_id, $this->namespace); |
997 |
997 |
998 profiler_log("PageProcessor [{$this->namespace}:{$this->page_id}]: Ran _setup()"); |
998 profiler_log("PageProcessor [{$this->namespace}:{$this->page_id}]: Ran _setup()"); |
999 } |
999 } |
1000 |
1000 |
1001 /** |
1001 /** |
1002 * Processes any redirects. |
1002 * Processes any redirects. |
1003 * @access private |
1003 * @access private |
1004 */ |
1004 */ |
1005 |
1005 |
1006 function process_redirects() |
1006 function process_redirects() |
1007 { |
1007 { |
1008 global $db, $session, $paths, $template, $plugins; // Common objects |
1008 global $db, $session, $paths, $template, $plugins; // Common objects |
1009 global $output, $lang; |
1009 global $output, $lang; |
1010 |
1010 |
1011 $this->redirect_stack = array(); |
1011 $this->redirect_stack = array(); |
1012 |
1012 |
1013 if ( !method_exists($this->ns, 'get_redirect') ) |
1013 if ( !method_exists($this->ns, 'get_redirect') ) |
1014 return true; |
1014 return true; |
1015 |
1015 |
1016 if ( !$this->allow_redir ) |
1016 if ( !$this->allow_redir ) |
1017 return true; |
1017 return true; |
1018 |
1018 |
1019 $redirect_count = 0; |
1019 $redirect_count = 0; |
1020 |
1020 |
1021 while ( $result = $this->ns->get_redirect() ) |
1021 while ( $result = $this->ns->get_redirect() ) |
1022 { |
1022 { |
1023 if ( $result['namespace'] == 'Special' || $result['namespace'] == 'Admin' ) |
1023 if ( $result['namespace'] == 'Special' || $result['namespace'] == 'Admin' ) |
1024 { |
1024 { |
1025 // Can't redirect to special/admin page |
1025 // Can't redirect to special/admin page |
1026 $this->redir_error = $lang->get('page_err_redirect_to_special'); |
1026 $this->redir_error = $lang->get('page_err_redirect_to_special'); |
1027 break; |
1027 break; |
1028 } |
1028 } |
1029 if ( $redirect_count == 3 ) |
1029 if ( $redirect_count == 3 ) |
1030 { |
1030 { |
1031 // max of 3 internal redirects exceeded |
1031 // max of 3 internal redirects exceeded |
1032 $this->redir_error = $lang->get('page_err_redirects_exceeded'); |
1032 $this->redir_error = $lang->get('page_err_redirects_exceeded'); |
1033 break; |
1033 break; |
1034 } |
1034 } |
1035 |
1035 |
1036 $loop = false; |
1036 $loop = false; |
1037 foreach ( $this->redirect_stack as $stackel ) |
1037 foreach ( $this->redirect_stack as $stackel ) |
1038 { |
1038 { |
1039 if ( $result['page_id'] == $stackel['old_page_id'] && $result['namespace'] == $stackel['old_namespace'] ) |
1039 if ( $result['page_id'] == $stackel['old_page_id'] && $result['namespace'] == $stackel['old_namespace'] ) |
1040 { |
1040 { |
1041 $loop = true; |
1041 $loop = true; |
1042 break; |
1042 break; |
1043 } |
1043 } |
1044 } |
1044 } |
1045 |
1045 |
1046 if ( $loop ) |
1046 if ( $loop ) |
1047 { |
1047 { |
1048 // redirect loop |
1048 // redirect loop |
1049 $this->redir_error = $lang->get('page_err_redirect_infinite_loop'); |
1049 $this->redir_error = $lang->get('page_err_redirect_infinite_loop'); |
1050 break; |
1050 break; |
1051 } |
1051 } |
1052 $new_ns = namespace_factory($result['page_id'], $result['namespace']); |
1052 $new_ns = namespace_factory($result['page_id'], $result['namespace']); |
1053 if ( !$new_ns->exists() ) |
1053 if ( !$new_ns->exists() ) |
1054 { |
1054 { |
1055 // new page doesn't exist |
1055 // new page doesn't exist |
1056 $this->redir_error = $lang->get('page_err_redirect_to_nonexistent'); |
1056 $this->redir_error = $lang->get('page_err_redirect_to_nonexistent'); |
1057 break; |
1057 break; |
1058 } |
1058 } |
1059 |
1059 |
1060 // build stack entry |
1060 // build stack entry |
1061 $stackel = array( |
1061 $stackel = array( |
1062 'page_id' => $result['page_id'], |
1062 'page_id' => $result['page_id'], |
1063 'namespace' => $result['namespace'], |
1063 'namespace' => $result['namespace'], |
1064 'old_page_id' => $this->page_id, |
1064 'old_page_id' => $this->page_id, |
1065 'old_namespace' => $this->namespace, |
1065 'old_namespace' => $this->namespace, |
1066 'old_title' => $this->ns->title |
1066 'old_title' => $this->ns->title |
1067 ); |
1067 ); |
1068 |
1068 |
1069 // replace everything (perform the actual redirect) |
1069 // replace everything (perform the actual redirect) |
1070 $this->ns = $new_ns; |
1070 $this->ns = $new_ns; |
1071 |
1071 |
1072 $this->page_id =& $this->ns->page_id; |
1072 $this->page_id =& $this->ns->page_id; |
1073 $this->namespace =& $this->ns->namespace; |
1073 $this->namespace =& $this->ns->namespace; |
1074 |
1074 |
1075 $this->redirect_stack[] = $stackel; |
1075 $this->redirect_stack[] = $stackel; |
1076 |
1076 |
1077 $redirect_count++; |
1077 $redirect_count++; |
1078 } |
1078 } |
1079 } |
1079 } |
1080 |
1080 |
1081 /** |
1081 /** |
1082 * Sends the page header, dependent on, of course, whether we're supposed to. |
1082 * Sends the page header, dependent on, of course, whether we're supposed to. |
1083 */ |
1083 */ |
1084 |
1084 |
1085 function header() |
1085 function header() |
1086 { |
1086 { |
1087 global $db, $session, $paths, $template, $plugins; // Common objects |
1087 global $db, $session, $paths, $template, $plugins; // Common objects |
1088 if ( $this->send_headers ) |
1088 if ( $this->send_headers ) |
1089 $template->header(); |
1089 $template->header(); |
1090 } |
1090 } |
1091 |
1091 |
1092 /** |
1092 /** |
1093 * Sends the page footer, dependent on, of course, whether we're supposed to. |
1093 * Sends the page footer, dependent on, of course, whether we're supposed to. |
1094 */ |
1094 */ |
1095 |
1095 |
1096 function footer() |
1096 function footer() |
1097 { |
1097 { |
1098 global $db, $session, $paths, $template, $plugins; // Common objects |
1098 global $db, $session, $paths, $template, $plugins; // Common objects |
1099 if ( $this->send_headers ) |
1099 if ( $this->send_headers ) |
1100 $template->footer(); |
1100 $template->footer(); |
1101 } |
1101 } |
1102 |
1102 |
1103 /** |
1103 /** |
1104 * Fetches the raw, unfiltered page text. |
1104 * Fetches the raw, unfiltered page text. |
1105 * @access public |
1105 * @access public |
1106 */ |
1106 */ |
1107 |
1107 |
1108 function fetch_text() |
1108 function fetch_text() |
1109 { |
1109 { |
1110 return $this->ns->fetch_text(); |
1110 return $this->ns->fetch_text(); |
1111 } |
1111 } |
1112 |
1112 |
1113 /** |
1113 /** |
1114 * Tells us if the page exists. |
1114 * Tells us if the page exists. |
1115 * @return bool |
1115 * @return bool |
1116 */ |
1116 */ |
1117 |
1117 |
1118 function exists() |
1118 function exists() |
1119 { |
1119 { |
1120 return $this->ns->exists(); |
1120 return $this->ns->exists(); |
1121 } |
1121 } |
1122 |
1122 |
1123 /** |
1123 /** |
1124 * Send the error message to the user that the access to this page is denied. |
1124 * Send the error message to the user that the access to this page is denied. |
1125 * @access private |
1125 * @access private |
1126 */ |
1126 */ |
1127 |
1127 |
1128 function err_access_denied() |
1128 function err_access_denied() |
1129 { |
1129 { |
1130 global $db, $session, $paths, $template, $plugins; // Common objects |
1130 global $db, $session, $paths, $template, $plugins; // Common objects |
1131 global $lang; |
1131 global $lang; |
1132 global $email; |
1132 global $email; |
1133 |
1133 |
1134 // Log it for crying out loud |
1134 // Log it for crying out loud |
1135 $q = $db->sql_query('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,author_uid,edit_summary,page_text) VALUES(\'security\', \'illegal_page\', '.time().', \'DEPRECATED\', \''.$db->escape($session->username).'\', ' . $session->user_id . ', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', \'' . $db->escape(serialize(array($this->page_id, $this->namespace))) . '\')'); |
1135 $q = $db->sql_query('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,author_uid,edit_summary,page_text) VALUES(\'security\', \'illegal_page\', '.time().', \'DEPRECATED\', \''.$db->escape($session->username).'\', ' . $session->user_id . ', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', \'' . $db->escape(serialize(array($this->page_id, $this->namespace))) . '\')'); |
1136 |
1136 |
1137 $ob = ''; |
1137 $ob = ''; |
1138 //$template->tpl_strings['PAGE_NAME'] = 'Access denied'; |
1138 //$template->tpl_strings['PAGE_NAME'] = 'Access denied'; |
1139 $template->tpl_strings['PAGE_NAME'] = htmlspecialchars( $this->title ); |
1139 $template->tpl_strings['PAGE_NAME'] = htmlspecialchars( $this->title ); |
1140 |
1140 |
1141 if ( $this->send_headers ) |
1141 if ( $this->send_headers ) |
1142 { |
1142 { |
1143 $ob .= $template->getHeader(); |
1143 $ob .= $template->getHeader(); |
1144 } |
1144 } |
1145 |
1145 |
1146 if ( count($this->redirect_stack) > 0 ) |
1146 if ( count($this->redirect_stack) > 0 ) |
1147 { |
1147 { |
1148 $stack = array_reverse($this->redirect_stack); |
1148 $stack = array_reverse($this->redirect_stack); |
1149 foreach ( $stack as $oldtarget ) |
1149 foreach ( $stack as $oldtarget ) |
1150 { |
1150 { |
1151 $url = makeUrlNS($oldtarget[1], $oldtarget[0], 'redirect=no', true); |
1151 $url = makeUrlNS($oldtarget[1], $oldtarget[0], 'redirect=no', true); |
1152 $old_page = namespace_factory($oldtarget[0], $oldtarget[1]); |
1152 $old_page = namespace_factory($oldtarget[0], $oldtarget[1]); |
1153 $page_data = $old_page->get_cdata(); |
1153 $page_data = $old_page->get_cdata(); |
1154 $title = ( isset($page_data['name']) ) ? $page_data['name'] : $paths->nslist[$oldtarget[1]] . htmlspecialchars( str_replace('_', ' ', dirtify_page_id( $oldtarget[0] ) ) ); |
1154 $title = ( isset($page_data['name']) ) ? $page_data['name'] : $paths->nslist[$oldtarget[1]] . htmlspecialchars( str_replace('_', ' ', dirtify_page_id( $oldtarget[0] ) ) ); |
1155 $a = '<a href="' . $url . '">' . $title . '</a>'; |
1155 $a = '<a href="' . $url . '">' . $title . '</a>'; |
1156 |
1156 |
1157 $url = makeUrlNS($this->namespace, $this->page_id, 'redirect=no', true); |
1157 $url = makeUrlNS($this->namespace, $this->page_id, 'redirect=no', true); |
1158 $page_data = $this->ns->get_cdata(); |
1158 $page_data = $this->ns->get_cdata(); |
1159 $title = ( isset($page_data['name']) ) ? $page_data['name'] : $paths->nslist[$this->namespace] . htmlspecialchars( str_replace('_', ' ', dirtify_page_id( $this->page_id ) ) ); |
1159 $title = ( isset($page_data['name']) ) ? $page_data['name'] : $paths->nslist[$this->namespace] . htmlspecialchars( str_replace('_', ' ', dirtify_page_id( $this->page_id ) ) ); |
1160 $b = '<a href="' . $url . '">' . $title . '</a>'; |
1160 $b = '<a href="' . $url . '">' . $title . '</a>'; |
1161 |
1161 |
1162 $ob .= '<small>' . $lang->get('page_msg_redirected_from_to', array('from' => $a, 'to' => $b)) . '<br /></small>'; |
1162 $ob .= '<small>' . $lang->get('page_msg_redirected_from_to', array('from' => $a, 'to' => $b)) . '<br /></small>'; |
1163 } |
1163 } |
1164 } |
1164 } |
1165 |
1165 |
1166 $email_link = $email->encryptEmail(getConfig('contact_email'), '', '', $lang->get('page_err_access_denied_siteadmin')); |
1166 $email_link = $email->encryptEmail(getConfig('contact_email'), '', '', $lang->get('page_err_access_denied_siteadmin')); |
1167 |
1167 |
1168 $ob .= "<h3>" . $lang->get('page_err_access_denied_title') . "</h3>"; |
1168 $ob .= "<h3>" . $lang->get('page_err_access_denied_title') . "</h3>"; |
1169 $ob .= "<p>" . $lang->get('page_err_access_denied_body', array('site_administration' => $email_link)) . "</p>"; |
1169 $ob .= "<p>" . $lang->get('page_err_access_denied_body', array('site_administration' => $email_link)) . "</p>"; |
1170 |
1170 |
1171 if ( $this->send_headers ) |
1171 if ( $this->send_headers ) |
1172 { |
1172 { |
1173 $ob .= $template->getFooter(); |
1173 $ob .= $template->getFooter(); |
1174 } |
1174 } |
1175 echo $ob; |
1175 echo $ob; |
1176 } |
1176 } |
1177 |
1177 |
1178 /** |
1178 /** |
1179 * Inform the user of an incorrect or absent password |
1179 * Inform the user of an incorrect or absent password |
1180 * @access private |
1180 * @access private |
1181 */ |
1181 */ |
1182 |
1182 |
1183 function err_wrong_password() |
1183 function err_wrong_password() |
1184 { |
1184 { |
1185 global $db, $session, $paths, $template, $plugins; // Common objects |
1185 global $db, $session, $paths, $template, $plugins; // Common objects |
1186 global $lang; |
1186 global $lang; |
1187 |
1187 |
1188 $title = $lang->get('page_msg_passrequired_title'); |
1188 $title = $lang->get('page_msg_passrequired_title'); |
1189 $message = ( empty($this->password) ) ? |
1189 $message = ( empty($this->password) ) ? |
1190 '<p>' . $lang->get('page_msg_passrequired') . '</p>' : |
1190 '<p>' . $lang->get('page_msg_passrequired') . '</p>' : |
1191 '<p>' . $lang->get('page_msg_pass_wrong') . '</p>'; |
1191 '<p>' . $lang->get('page_msg_pass_wrong') . '</p>'; |
1192 $message .= '<form action="' . makeUrlNS($this->namespace, $this->page_id) . '" method="post"> |
1192 $message .= '<form action="' . makeUrlNS($this->namespace, $this->page_id) . '" method="post"> |
1193 <p> |
1193 <p> |
1194 <label>' . $lang->get('page_lbl_password') . ' <input name="pagepass" type="password" /></label> <input type="submit" value="' . $lang->get('page_btn_password_submit') . '" /> |
1194 <label>' . $lang->get('page_lbl_password') . ' <input name="pagepass" type="password" /></label> <input type="submit" value="' . $lang->get('page_btn_password_submit') . '" /> |
1195 </p> |
1195 </p> |
1196 </form>'; |
1196 </form>'; |
1197 if ( $this->send_headers ) |
1197 if ( $this->send_headers ) |
1198 { |
1198 { |
1199 $template->tpl_strings['PAGE_NAME'] = $title; |
1199 $template->tpl_strings['PAGE_NAME'] = $title; |
1200 $template->header(); |
1200 $template->header(); |
1201 echo "$message"; |
1201 echo "$message"; |
1202 $template->footer(); |
1202 $template->footer(); |
1203 } |
1203 } |
1204 else |
1204 else |
1205 { |
1205 { |
1206 echo "<h2>$title</h2> |
1206 echo "<h2>$title</h2> |
1207 $message"; |
1207 $message"; |
1208 } |
1208 } |
1209 } |
1209 } |
1210 |
1210 |
1211 /** |
1211 /** |
1212 * Send the error message to the user complaining that there weren't any rows. |
1212 * Send the error message to the user complaining that there weren't any rows. |
1213 * @access private |
1213 * @access private |
1214 */ |
1214 */ |
1215 |
1215 |
1216 function err_no_rows() |
1216 function err_no_rows() |
1217 { |
1217 { |
1218 global $db, $session, $paths, $template, $plugins; // Common objects |
1218 global $db, $session, $paths, $template, $plugins; // Common objects |
1219 |
1219 |
1220 $title = 'No text rows'; |
1220 $title = 'No text rows'; |
1221 $message = 'While the page\'s existence was verified, there were no rows in the database that matched the query for the text. This may indicate a bug with the software; ask the webmaster for more information. The offending query was:<pre>' . $db->latest_query . '</pre>'; |
1221 $message = 'While the page\'s existence was verified, there were no rows in the database that matched the query for the text. This may indicate a bug with the software; ask the webmaster for more information. The offending query was:<pre>' . $db->latest_query . '</pre>'; |
1222 if ( $this->send_headers ) |
1222 if ( $this->send_headers ) |
1223 { |
1223 { |
1224 $template->tpl_strings['PAGE_NAME'] = $title; |
1224 $template->tpl_strings['PAGE_NAME'] = $title; |
1225 $template->header(); |
1225 $template->header(); |
1226 echo "<p>$message</p>"; |
1226 echo "<p>$message</p>"; |
1227 $template->footer(); |
1227 $template->footer(); |
1228 } |
1228 } |
1229 else |
1229 else |
1230 { |
1230 { |
1231 echo "<h2>$title</h2> |
1231 echo "<h2>$title</h2> |
1232 <p>$message</p>"; |
1232 <p>$message</p>"; |
1233 } |
1233 } |
1234 } |
1234 } |
1235 |
1235 |
1236 /** |
1236 /** |
1237 * Send an error message and die. For debugging or critical technical errors only - nothing that would under normal circumstances be shown to the user. |
1237 * Send an error message and die. For debugging or critical technical errors only - nothing that would under normal circumstances be shown to the user. |
1238 * @param string Error message |
1238 * @param string Error message |
1239 * @param bool If true, send DBAL's debugging information as well |
1239 * @param bool If true, send DBAL's debugging information as well |
1240 */ |
1240 */ |
1241 |
1241 |
1242 function send_error($message, $sql = false) |
1242 function send_error($message, $sql = false) |
1243 { |
1243 { |
1244 global $db, $session, $paths, $template, $plugins; // Common objects |
1244 global $db, $session, $paths, $template, $plugins; // Common objects |
1245 global $lang; |
1245 global $lang; |
1246 |
1246 |
1247 $content = "<p>$message</p>"; |
1247 $content = "<p>$message</p>"; |
1248 $template->tpl_strings['PAGE_NAME'] = $lang->get('page_msg_general_error'); |
1248 $template->tpl_strings['PAGE_NAME'] = $lang->get('page_msg_general_error'); |
1249 |
1249 |
1250 if ( $this->debug['works'] ) |
1250 if ( $this->debug['works'] ) |
1251 { |
1251 { |
1252 $content .= $this->debug['backtrace']; |
1252 $content .= $this->debug['backtrace']; |
1253 } |
1253 } |
1254 |
1254 |
1255 header('HTTP/1.1 500 Internal Server Error'); |
1255 header('HTTP/1.1 500 Internal Server Error'); |
1256 |
1256 |
1257 $template->header(); |
1257 $template->header(); |
1258 echo $content; |
1258 echo $content; |
1259 $template->footer(); |
1259 $template->footer(); |
1260 |
1260 |
1261 $db->close(); |
1261 $db->close(); |
1262 |
1262 |
1263 exit; |
1263 exit; |
1264 |
1264 |
1265 } |
1265 } |
1266 |
1266 |
1267 /** |
1267 /** |
1268 * Raises an error. |
1268 * Raises an error. |
1269 * @param string Error string |
1269 * @param string Error string |
1270 */ |
1270 */ |
1271 |
1271 |
1272 function raise_error($string) |
1272 function raise_error($string) |
1273 { |
1273 { |
1274 if ( !is_string($string) ) |
1274 if ( !is_string($string) ) |
1275 return false; |
1275 return false; |
1276 $this->_errors[] = $string; |
1276 $this->_errors[] = $string; |
1277 } |
1277 } |
1278 |
1278 |
1279 /** |
1279 /** |
1280 * Retrieves the latest error from the error stack and returns it ('pops' the error stack) |
1280 * Retrieves the latest error from the error stack and returns it ('pops' the error stack) |
1281 * @return string |
1281 * @return string |
1282 */ |
1282 */ |
1283 |
1283 |
1284 function pop_error() |
1284 function pop_error() |
1285 { |
1285 { |
1286 if ( count($this->_errors) < 1 ) |
1286 if ( count($this->_errors) < 1 ) |
1287 return false; |
1287 return false; |
1288 return array_pop($this->_errors); |
1288 return array_pop($this->_errors); |
1289 } |
1289 } |
1290 |
1290 |
1291 } // class PageProcessor |
1291 } // class PageProcessor |
1292 |
1292 |
1293 ?> |
1293 ?> |