includes/functions.php
changeset 229 97ae8e9d5e29
parent 228 b0a4d179be85
child 231 b11a2f1353c0
--- a/includes/functions.php	Thu Sep 27 15:55:37 2007 -0400
+++ b/includes/functions.php	Sat Nov 03 07:43:35 2007 -0400
@@ -273,15 +273,19 @@
  * @param string $timeout Timeout, in seconds, to delay the redirect. Defaults to 3.
  */
 
-function redirect($url, $title = 'Redirecting...', $message = 'Please wait while you are redirected.', $timeout = 3)
+function redirect($url, $title = 'etc_redirect_title', $message = 'etc_redirect_body', $timeout = 3)
 {
   global $db, $session, $paths, $template, $plugins; // Common objects
+  global $lang;
 
   if ( $timeout == 0 )
   {
     header('Location: ' . $url);
     header('HTTP/1.1 307 Temporary Redirect');
   }
+  
+  $title = $lang->get($title);
+  $message = $lang->get($message);
 
   $template->add_header('<meta http-equiv="refresh" content="' . $timeout . '; url=' . str_replace('"', '\\"', $url) . '" />');
   $template->add_header('<script type="text/javascript">
@@ -295,7 +299,12 @@
 
   $template->tpl_strings['PAGE_NAME'] = $title;
   $template->header(true);
-  echo '<p>' . $message . '</p><p>If you are not redirected within ' . ( $timeout + 1 ) . ' seconds, <a href="' . str_replace('"', '\\"', $url) . '">please click here</a>.</p>';
+  echo '<p>' . $message . '</p>';
+  $subst = array(
+      'timeout' => ( $timeout + 1 ),
+      'redirect_url' => str_replace('"', '\\"', $url)
+    );
+  echo '<p>' . $lang->get('etc_redirect_timeout', $subst) . '</p>';
   $template->footer(true);
 
   $db->close();
@@ -423,7 +432,9 @@
   $str = '0x';
   foreach($nums as $n)
   {
-    $str .= (string)dechex($n);
+    $byte = (string)dechex($n);
+    if ( strlen($byte) < 2 )
+      $byte = '0' . $byte;
   }
   return $str;
 }
@@ -630,6 +641,7 @@
 function show_category_info()
 {
   global $db, $session, $paths, $template, $plugins; // Common objects
+  global $lang;
   
   if ( $paths->namespace == 'Category' )
   {
@@ -745,9 +757,9 @@
   {
     echo '<div class="mdg-comment" style="margin: 10px 0 0 0;" id="category_box_wrapper">';
     echo '<div style="float: right;">';
-    echo '(<a href="#" onclick="ajaxCatToTag(); return false;">show page tags</a>)';
+    echo '(<a href="#" onclick="ajaxCatToTag(); return false;">' . $lang->get('tags_catbox_link') . '</a>)';
     echo '</div>';
-    echo '<div id="mdgCatBox">Categories: ';
+    echo '<div id="mdgCatBox">' . $lang->get('catedit_catbox_lbl_categories') . ' ';
     
     $where = '( c.page_id=\'' . $db->escape($paths->cpage['urlname_nons']) . '\' AND c.namespace=\'' . $db->escape($paths->namespace) . '\' )';
     $prefix = table_prefix;
@@ -777,13 +789,13 @@
     }
     else
     {
-      echo '(Uncategorized)';
+      echo $lang->get('catedit_catbox_lbl_uncategorized');
     }
     
     $can_edit = ( $session->get_permissions('edit_cat') && ( !$paths->page_protected || $session->get_permissions('even_when_protected') ) );
     if ( $can_edit )
     {
-      $edit_link = '<a href="' . makeUrl($paths->page, 'do=catedit', true) . '" onclick="ajaxCatEdit(); return false;">edit categorization</a>';
+      $edit_link = '<a href="' . makeUrl($paths->page, 'do=catedit', true) . '" onclick="ajaxCatEdit(); return false;">' . $lang->get('catedit_catbox_link_edit') . '</a>';
       echo ' [ ' . $edit_link . ' ]';
     }
     
@@ -874,23 +886,19 @@
 function display_page_headers()
 {
   global $db, $session, $paths, $template, $plugins; // Common objects
+  global $lang;
   if($session->get_permissions('vote_reset') && $paths->cpage['delvotes'] > 0)
   {
     $delvote_ips = unserialize($paths->cpage['delvote_ips']);
     $hr = htmlspecialchars(implode(', ', $delvote_ips['u']));
-    $is = 'is';
-    $s = '';
-    $s2 = 's';
-    if ( $paths->cpage['delvotes'] > 1)
-    {
-      $is = 'are';
-      $s = 's';
-      $s2 = '';
-    }
+    
+    $string_id = ( $paths->cpage['delvotes'] == 1 ) ? 'delvote_lbl_votes_one' : 'delvote_lbl_votes_plural';
+    $string = $lang->get($string_id, array('num_users' => $paths->cpage['delvotes']));
+    
     echo '<div class="info-box" style="margin-left: 0; margin-top: 5px;" id="mdgDeleteVoteNoticeBox">
-            <b>Notice:</b> There '.$is.' '.$paths->cpage['delvotes'].' user'.$s.' that think'.$s2.' this page should be deleted.<br />
-            <b>Users that voted:</b> ' . $hr . '<br />
-            <a href="'.makeUrl($paths->page, 'do=deletepage').'" onclick="ajaxDeletePage(); return false;">Delete page</a>  |  <a href="'.makeUrl($paths->page, 'do=resetvotes').'" onclick="ajaxResetDelVotes(); return false;">Reset votes</a>
+            <b>' . $lang->get('etc_lbl_notice') . '</b> ' . $string . '<br />
+            <b>' . $lang->get('delvote_lbl_users_that_voted') . '</b> ' . $hr . '<br />
+            <a href="'.makeUrl($paths->page, 'do=deletepage').'" onclick="ajaxDeletePage(); return false;">' . $lang->get('delvote_btn_deletepage') . '</a>  |  <a href="'.makeUrl($paths->page, 'do=resetvotes').'" onclick="ajaxResetDelVotes(); return false;">' . $lang->get('delvote_btn_resetvotes') . '</a>
           </div>';
   }
 }
@@ -1789,6 +1797,26 @@
 
 function sanitize_html($html, $filter_php = true)
 {
+  // Random seed for substitution
+  $rand_seed = md5( sha1(microtime()) . mt_rand() );
+  
+  // Strip out comments that are already escaped
+  preg_match_all('/&lt;!--(.*?)--&gt;/', $html, $comment_match);
+  $i = 0;
+  foreach ( $comment_match[0] as $comment )
+  {
+    $html = str_replace_once($comment, "{HTMLCOMMENT:$i:$rand_seed}", $html);
+    $i++;
+  }
+  
+  // Strip out code sections that will be postprocessed by Text_Wiki
+  preg_match_all(';^<code(\s[^>]*)?>((?:(?R)|.)*?)\n</code>(\s|$);msi', $html, $code_match);
+  $i = 0;
+  foreach ( $code_match[0] as $code )
+  {
+    $html = str_replace_once($code, "{TW_CODE:$i:$rand_seed}", $html);
+    $i++;
+  }
 
   $html = preg_replace('#<([a-z]+)([\s]+)([^>]+?)'.htmlalternatives('javascript:').'(.+?)>(.*?)</\\1>#is', '&lt;\\1\\2\\3javascript:\\59&gt;\\60&lt;/\\1&gt;', $html);
   $html = preg_replace('#<([a-z]+)([\s]+)([^>]+?)'.htmlalternatives('javascript:').'(.+?)>#is', '&lt;\\1\\2\\3javascript:\\59&gt;', $html);
@@ -1802,6 +1830,8 @@
   $tag_whitelist = array_keys ( setupAttributeWhitelist() );
   if ( !$filter_php )
     $tag_whitelist[] = '?php';
+  // allow HTML comments
+  $tag_whitelist[] = '!--';
   $len = strlen($html);
   $in_quote = false;
   $quote_char = '';
@@ -1862,8 +1892,12 @@
       }
       else
       {
+        // If not filtering PHP, don't bother to strip
         if ( $tag_name == '?php' && !$filter_php )
           continue;
+        // If this is a comment, likewise skip this "tag"
+        if ( $tag_name == '!--' )
+          continue;
         $f = fixTagAttributes( $attribs_only, $tag_name );
         $s = ( empty($f) ) ? '' : ' ';
 
@@ -1891,15 +1925,28 @@
     }
 
   }
-
+  
   // Vulnerability from ha.ckers.org/xss.html:
   // <script src="http://foo.com/xss.js"
   // <
   // The rule is so specific because everything else will have been filtered by now
   $html = preg_replace('/<(script|iframe)(.+?)src=([^>]*)</i', '&lt;\\1\\2src=\\3&lt;', $html);
 
-  // Unstrip comments
-  $html = preg_replace('/&lt;!--([^>]*?)--&gt;/i', '', $html);
+  // Restore stripped comments
+  $i = 0;
+  foreach ( $comment_match[0] as $comment )
+  {
+    $html = str_replace_once("{HTMLCOMMENT:$i:$rand_seed}", $comment, $html);
+    $i++;
+  }
+  
+  // Restore stripped code
+  $i = 0;
+  foreach ( $code_match[0] as $code )
+  {
+    $html = str_replace_once("{TW_CODE:$i:$rand_seed}", $code, $html);
+    $i++;
+  }
 
   return $html;
 
@@ -2705,7 +2752,7 @@
 function sanitize_tag($tag)
 {
   $tag = strtolower($tag);
-  $tag = preg_replace('/[^\w _-]+/', '', $tag);
+  $tag = preg_replace('/[^\w _@\$%\^&-]+/', '', $tag);
   $tag = trim($tag);
   return $tag;
 }
@@ -2757,7 +2804,7 @@
   $strip_tags = implode('|', $strip_tags);
   
   // Strip out the tags and replace with placeholders
-  preg_match_all("#<($strip_tags)(.*?)>(.*?)</($strip_tags)>#is", $html, $matches);
+  preg_match_all("#<($strip_tags)([ ]+.*?)?>(.*?)</($strip_tags)>#is", $html, $matches);
   $seed = md5(microtime() . mt_rand()); // Random value used for placeholders
   for ($i = 0;$i < sizeof($matches[1]); $i++)
   {
@@ -2765,7 +2812,7 @@
   }
   
   // Optimize (but don't obfuscate) Javascript
-  preg_match_all('/<script(.*?)>(.+?)<\/script>/is', $html, $jscript);
+  preg_match_all('/<script([ ]+.*?)?>(.*?)(\]\]>)?<\/script>/is', $html, $jscript);
   
   // list of Javascript reserved words - from about.com
   $reserved_words = array('abstract', 'as', 'boolean', 'break', 'byte', 'case', 'catch', 'char', 'class', 'continue', 'const', 'debugger', 'default', 'delete', 'do',
@@ -2780,6 +2827,8 @@
   {
     $js =& $jscript[2][$i];
     
+    // echo('<pre>' . "-----------------------------------------------------------------------------\n" . htmlspecialchars($js) . '</pre>');
+    
     // for line optimization, explode it
     $particles = explode("\n", $js);
     
@@ -3127,6 +3176,53 @@
   return $score;
 }
 
+/**
+ * Installs a language.
+ * @param string The ISO-639-3 identifier for the language. Maximum of 6 characters, usually 3.
+ * @param string The name of the language in English (Spanish)
+ * @param string The name of the language natively (EspaƱol)
+ * @param string The path to the file containing the language's strings. Optional.
+ */
+
+function install_language($lang_code, $lang_name_neutral, $lang_name_local, $lang_file = false)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  
+  $q = $db->sql_query('SELECT 1 FROM '.table_prefix.'language WHERE lang_code = "' . $db->escape($lang_code) . '";');
+  if ( !$q )
+    $db->_die('functions.php - checking for language existence');
+  
+  if ( $db->numrows() > 0 )
+    // Language already exists
+    return false;
+  
+  $q = $db->sql_query('INSERT INTO ' . table_prefix . 'language(lang_code, lang_name_default, lang_name_native) 
+                         VALUES(
+                           "' . $db->escape($lang_code) . '",
+                           "' . $db->escape($lang_name_neutral) . '",
+                           "' . $db->escape($lang_name_native) . '"
+                         );');
+  if ( !$q )
+    $db->_die('functions.php - installing language');
+  
+  $lang_id = $db->insert_id();
+  if ( empty($lang_id) )
+    return false;
+  
+  // Do we also need to install a language file?
+  if ( is_string($lang_file) && file_exists($lang_file) )
+  {
+    $lang = new Language($lang_id);
+    $lang->import($lang_file);
+  }
+  else if ( is_string($lang_file) && !file_exists($lang_file) )
+  {
+    echo '<b>Notice:</b> Can\'t load language file, so the specified language wasn\'t fully installed.<br />';
+    return false;
+  }
+  return true;
+}
+
 //die('<pre>Original:  01010101010100101010100101010101011010'."\nProcessed: ".uncompress_bitfield(compress_bitfield('01010101010100101010100101010101011010')).'</pre>');
 
 ?>