[ Index ]

PHP Cross Reference of MyBB 1.6.5

title

Body

[close]

/admin/inc/ -> functions_themes.php (source)

   1  <?php
   2  /**
   3   * Import an entire theme (stylesheets, properties & templates) from an XML file.
   4   *
   5   * @param string The contents of the XML file
   6   * @param array Optional array of options or overrides
   7   * @return boolean True on success, false on failure
   8   */
   9  function import_theme_xml($xml, $options=array())
  10  {
  11      global $mybb, $db;
  12      
  13      require_once  MYBB_ROOT."inc/class_xml.php";
  14  
  15      $parser = new XMLParser($xml);
  16      $tree = $parser->get_tree();
  17  
  18      if(!is_array($tree) || !is_array($tree['theme']))
  19      {
  20          return -1;
  21      }
  22      
  23      $theme = $tree['theme'];
  24      
  25      // Do we have MyBB 1.2 template's we're importing?
  26      $css_120 = "";
  27      
  28      if(is_array($theme['cssbits']))
  29      {
  30          $cssbits = kill_tags($theme['cssbits']);
  31          
  32          foreach($cssbits as $name => $values)
  33          {
  34              $css_120 .= "{$name} {\n";
  35              foreach($values as $property => $value)
  36              {
  37                  if(is_array($value))
  38                  {
  39                      $property = str_replace('_', ':', $property);
  40                      
  41                      $css_120 .= "}\n{$name} {$property} {\n";
  42                      foreach($value as $property2 => $value2)
  43                      {
  44                          $css_120 .= "\t{$property2}: {$value2}\n";
  45                      }
  46                  }
  47                  else
  48                  {
  49                      $css_120 .= "\t{$property}: {$value}\n";
  50                  }
  51              }
  52              $css_120 .= "}\n";
  53          }
  54      }
  55      
  56      if(is_array($theme['themebits']))
  57      {
  58          $themebits = kill_tags($theme['themebits']);
  59          
  60          $theme['properties']['tag'] = 'properties';
  61          
  62          foreach($themebits as $name => $value)
  63          {
  64              if($name == "extracss")
  65              {
  66                  $css_120 .= $value;
  67                  continue;
  68              }
  69              
  70              $theme['properties'][$name] = $value;
  71          }
  72      }
  73      
  74      if($css_120)
  75      {
  76          $css_120 = upgrade_css_120_to_140($css_120);
  77          $theme['stylesheets']['tag'] = 'stylesheets';
  78          $theme['stylesheets']['stylesheet'][0]['tag'] = 'stylesheet';
  79          $theme['stylesheets']['stylesheet'][0]['attributes'] = array('name' => 'global.css', 'version' => $mybb->version_code);
  80          $theme['stylesheets']['stylesheet'][0]['value'] = $css_120;
  81          
  82          unset($theme['cssbits']);
  83          unset($theme['themebits']);
  84      }
  85      
  86      if(is_array($theme['properties']))
  87      {
  88          foreach($theme['properties'] as $property => $value)
  89          {
  90              if($property == "tag" || $property == "value")
  91              {
  92                  continue;
  93              }
  94              
  95              $properties[$property] = $value['value'];
  96          }
  97      }
  98      
  99      if(empty($mybb->input['name']))
 100      {
 101          $name = $theme['attributes']['name'];
 102      }
 103      else
 104      {
 105          $name = $mybb->input['name'];
 106      }
 107      $version = $theme['attributes']['version'];
 108  
 109      $query = $db->simple_select("themes", "tid", "name='".$db->escape_string($name)."'", array("limit" => 1));
 110      $existingtheme = $db->fetch_array($query);
 111      if($options['force_name_check'] && $existingtheme['tid'])
 112      {
 113          return -3;
 114      }
 115      else if($existingtheme['tid'])
 116      {
 117          $options['tid'] = $existingtheme['tid'];
 118      }
 119  
 120      if($mybb->version_code != $version && $options['version_compat'] != 1)
 121      {
 122          return -2;
 123      }
 124      
 125      // Do we have any templates to insert?
 126      if(!empty($theme['templates']['template']) && !$options['no_templates'])
 127      {        
 128          if($options['templateset']) 
 129          { 
 130              $sid = $options['templateset'];
 131          } 
 132          else 
 133          { 
 134              $sid = $db->insert_query("templatesets", array('title' => $db->escape_string($name)." Templates"));
 135          }
 136          
 137          $templates = $theme['templates']['template'];
 138          if(is_array($templates))
 139          {
 140              // Theme only has one custom template
 141              if(array_key_exists("attributes", $templates))
 142              {
 143                  $templates = array($templates);
 144              }
 145          }
 146      
 147          foreach($templates as $template)
 148          {
 149              // PostgreSQL causes apache to stop sending content sometimes and 
 150              // causes the page to stop loading during many queries all at one time
 151              if($db->engine == "pgsql")
 152              {
 153                  echo " ";
 154                  flush();
 155              }
 156              
 157              $new_template = array(
 158                  "title" => $db->escape_string($template['attributes']['name']),
 159                  "template" => $db->escape_string($template['value']),
 160                  "sid" => $db->escape_string($sid),
 161                  "version" => $db->escape_string($template['attributes']['version']),
 162                  "dateline" => TIME_NOW
 163              );
 164              $db->insert_query("templates", $new_template);
 165          }
 166          
 167          $properties['templateset'] = $sid;
 168      }
 169  
 170      // Not overriding an existing theme
 171      if(!$options['tid'])
 172      {
 173          // Insert the theme
 174          $theme_id = build_new_theme($name, $properties, $options['parent']);
 175      }
 176      // Overriding an existing - delete refs.
 177      else
 178      {
 179          $db->delete_query("themestylesheets", "tid='{$options['tid']}'");
 180          $db->update_query("themes", array("properties" => $db->escape_string(serialize($properties))), "tid='{$options['tid']}'");
 181          $theme_id = $options['tid'];
 182      }
 183  
 184      // If we have any stylesheets, process them
 185      if(!empty($theme['stylesheets']['stylesheet']) && !$options['no_stylesheets'])
 186      {
 187          // Are we dealing with a single stylesheet?
 188          if(isset($theme['stylesheets']['stylesheet']['tag']))
 189          {
 190              // Trick the system into thinking we have a good array =P
 191              $theme['stylesheets']['stylesheet'] = array($theme['stylesheets']['stylesheet']);
 192          }
 193          
 194          foreach($theme['stylesheets']['stylesheet'] as $stylesheet)
 195          {
 196              if(!$stylesheet['attributes']['lastmodified'])
 197              {
 198                  $stylesheet['attributes']['lastmodified'] = TIME_NOW;
 199              }
 200              
 201              $new_stylesheet = array(
 202                  "name" => $db->escape_string($stylesheet['attributes']['name']),
 203                  "tid" => $theme_id,
 204                  "attachedto" => $db->escape_string($stylesheet['attributes']['attachedto']),
 205                  "stylesheet" => $db->escape_string($stylesheet['value']),
 206                  "lastmodified" => intval($stylesheet['attributes']['lastmodified']),
 207                  "cachefile" => $db->escape_string($stylesheet['attributes']['name'])
 208              );
 209              $sid = $db->insert_query("themestylesheets", $new_stylesheet);
 210              $css_url = "css.php?stylesheet={$sid}";
 211              $cached = cache_stylesheet($theme_id, $stylesheet['attributes']['name'], $stylesheet['value']);
 212              if($cached)
 213              {
 214                  $css_url = $cached;
 215              }
 216              
 217              $attachedto = $stylesheet['attributes']['attachedto'];
 218              if(!$attachedto)
 219              {
 220                  $attachedto = "global";
 221              }
 222              
 223              // private.php?compose,folders|usercp.php,global|global
 224              $attachedto = explode("|", $attachedto);
 225              foreach($attachedto as $attached_file)
 226              {
 227                  $attached_actions = explode(",", $attached_file);
 228                  $attached_file = array_shift($attached_actions);
 229                  if(count($attached_actions) == 0)
 230                  {
 231                      $attached_actions = array("global");
 232                  }
 233                  
 234                  foreach($attached_actions as $action)
 235                  {
 236                      $theme_stylesheets[$attached_file][$action][] = $css_url;
 237                  }
 238              }
 239          }
 240          // Now we have our list of built stylesheets, save them
 241          $updated_theme = array(
 242              "stylesheets" => $db->escape_string(serialize($theme_stylesheets))
 243          );
 244          $db->update_query("themes", $updated_theme, "tid='{$theme_id}'");
 245      }
 246      
 247      update_theme_stylesheet_list($theme_id);
 248  
 249      // And done?
 250      return $theme_id;
 251  }
 252  
 253  /**
 254   * Parse theme variables in a specific string.
 255   *
 256   * @param string The string to parse variables for
 257   * @param array Array of variables
 258   * @return string Parsed string with variables replaced
 259   */
 260  function parse_theme_variables($string, $variables=array())
 261  {
 262      foreach(array_keys($variables) as $variable) 
 263      {
 264          $find[] = "{{$variable}}";
 265          $replace[] = $variables[$variable];
 266      }
 267      return str_replace($find, $replace, $string);
 268  }
 269  
 270  /**
 271   * Caches a stylesheet to the file system.
 272   *
 273   * @param string The theme ID this stylesheet belongs to
 274   * @param string The name of the stylesheet
 275   * @param string The contents of the stylesheet
 276   */
 277  function cache_stylesheet($tid, $filename, $stylesheet)
 278  {
 279      global $mybb;
 280  
 281      $filename = str_replace('/', '', $filename);
 282      $tid = intval($tid);
 283  
 284      // If we're in safe mode save to the main theme folder by default
 285      if($mybb->safemode)
 286      {
 287          $theme_directory = "cache/themes";
 288          $filename = $tid."_".$filename;
 289      }
 290      // Does our theme directory exist? Try and create it.
 291      elseif(!is_dir(MYBB_ROOT."cache/themes/theme{$tid}"))
 292      {
 293          if(!@mkdir(MYBB_ROOT."cache/themes/theme{$tid}"))
 294          {
 295              $theme_directory = "cache/themes";
 296              $filename = $tid."_".$filename;
 297          }
 298          else
 299          {
 300              // Add in empty index.html!
 301              $fp = @fopen(MYBB_ROOT."cache/themes/theme{$tid}/index.html", "w");
 302              @fwrite($fp, "");
 303              @fclose($fp);
 304              
 305              $theme_directory = "cache/themes/theme{$tid}";
 306          }
 307      }
 308      // Seems like we're all good
 309      else
 310      {
 311          $theme_directory = "cache/themes/theme{$tid}";
 312      }
 313  
 314      $theme_vars = array(
 315          "theme" => $theme_directory
 316      );
 317      $stylesheet = parse_theme_variables($stylesheet, $theme_vars);
 318      $stylesheet = preg_replace("#url\((\"|'|)(.*)\\1\)#e", "fix_css_urls('$2')", $stylesheet);
 319      
 320      $fp = @fopen(MYBB_ROOT."{$theme_directory}/{$filename}", "wb");
 321      if(!$fp)
 322      {
 323          return false;
 324      }
 325      
 326      @fwrite($fp, $stylesheet);
 327      @fclose($fp);
 328      return "{$theme_directory}/{$filename}";
 329  }
 330  
 331  function resync_stylesheet($stylesheet)
 332  {
 333      global $db;
 334      
 335      // Try and fix any missing cache file names
 336      if(!$stylesheet['cachefile'] && $stylesheet['name'])
 337      {
 338          $stylesheet['cachefile'] = $stylesheet['name'];        
 339          $db->update_query("themestylesheets", array('cachefile' => $db->escape_string($stylesheet['name'])), "sid='{$stylesheet['sid']}'", 1);
 340      }
 341      
 342      // Still don't have the cache file name or is it not a flat file? Return false
 343      if(!$stylesheet['cachefile'] || strpos($stylesheet['cachefile'], 'css.php') !== false)
 344      {
 345          return false;
 346      }
 347      
 348      if(!file_exists(MYBB_ROOT."cache/themes/theme{$stylesheet['tid']}/{$stylesheet['name']}") && !file_exists(MYBB_ROOT."cache/themes/{$stylesheet['tid']}_{$stylesheet['name']}"))
 349      {
 350          if(cache_stylesheet($stylesheet['tid'], $stylesheet['cachefile'], $stylesheet['stylesheet']) !== false)
 351          {
 352              $db->update_query("themestylesheets", array('cachefile' => $db->escape_string($stylesheet['name'])), "sid='{$stylesheet['sid']}'", 1);
 353              
 354              update_theme_stylesheet_list($stylesheet['tid']);
 355              
 356              if($stylesheet['sid'] != 1)
 357              {
 358                  $db->update_query("themestylesheets", array('lastmodified' => TIME_NOW), "sid='{$stylesheet['sid']}'", 1);
 359              }
 360          }
 361      
 362          return true;
 363      }
 364      else if($stylesheet['sid'] != 1 && @filemtime(MYBB_ROOT."cache/themes/theme{$stylesheet['tid']}/{$stylesheet['name']}") > $stylesheet['lastmodified'])
 365      {
 366          $contents = unfix_css_urls(file_get_contents(MYBB_ROOT."cache/themes/theme{$stylesheet['tid']}/{$stylesheet['name']}"));
 367          $db->update_query("themestylesheets", array('stylesheet' => $db->escape_string($contents), 'lastmodified' => TIME_NOW), "sid='{$stylesheet['sid']}'", 1);
 368          return true;
 369      }
 370      
 371      return false;
 372  }
 373  
 374  function fix_css_urls($url)
 375  {
 376      if(!preg_match("#^([a-z0-9]+\:|/)#i", $url) && strpos($url, "../../../") === false)
 377      {
 378          return "url(../../../{$url})";
 379      }
 380      else
 381      {
 382          return "url({$url})";
 383      }
 384  }
 385  
 386  function unfix_css_urls($url)
 387  {
 388      return str_replace("../../../", "", $url);
 389  }
 390  
 391  /**
 392   * Build a theme based on the specified parameters.
 393   *
 394   * @param string The name of the theme
 395   * @param array Array of theme properties (if blank, inherits from parent)
 396   * @param int The parent ID for this theme (defaults to Master)
 397   * @return int The new theme ID
 398   */
 399  function build_new_theme($name, $properties=null, $parent=1)
 400  {
 401      global $db;
 402  
 403      $new_theme = array(
 404          "name" => $db->escape_string($name),
 405          "pid" => intval($parent),
 406          "def" => 0,
 407          "allowedgroups" => "all",
 408          "properties" => "",
 409          "stylesheets" => ""
 410      );
 411      $tid = $db->insert_query("themes", $new_theme);
 412  
 413      if($parent > 0)
 414      {
 415          $query = $db->simple_select("themes", "*", "tid='".intval($parent)."'");
 416          $parent_theme = $db->fetch_array($query);
 417          if(count($properties) == 0 || !is_array($properties))
 418          {
 419              $parent_properties = unserialize($parent_theme['properties']);
 420              if(!empty($parent_properties))
 421              {
 422                  foreach($parent_properties as $property => $value)
 423                  {
 424                      if($property == "inherited")
 425                      {
 426                          continue;
 427                      }
 428                      
 429                      $properties[$property] = $value;
 430                      if($parent_properties['inherited'][$property])
 431                      {
 432                          $properties['inherited'][$property] = $parent_properties['inherited'][$property];
 433                      }
 434                      else
 435                      {
 436                          $properties['inherited'][$property] = $parent;
 437                      }
 438                  }
 439                  $inherited_properties = true;
 440              }
 441          }
 442  
 443          if(count($stylesheets) == 0)
 444          {
 445              $parent_stylesheets = unserialize($parent_theme['stylesheets']);
 446              if(!empty($parent_stylesheets))
 447              {
 448                  foreach($parent_stylesheets as $location => $value)
 449                  {
 450                      if($location == "inherited")
 451                      {
 452                          continue;
 453                      }
 454                      
 455                      foreach($value as $action => $sheets)
 456                      {
 457                          foreach($sheets as $stylesheet)
 458                          {
 459                              $stylesheets[$location][$action][] = $stylesheet;
 460                              $inherited_check = "{$location}_{$action}";
 461                              if($parent_stylesheets['inherited'][$inherited_check][$stylesheet])
 462                              {
 463                                  $stylesheets['inherited'][$inherited_check][$stylesheet] = $parent_stylesheets['inherited'][$inherited_check][$stylesheet];
 464                              }
 465                              else
 466                              {
 467                                  $stylesheets['inherited'][$inherited_check][$stylesheet] = $parent;
 468                              }
 469                          }
 470                      }
 471                  }
 472                  $inherited_stylesheets = true;
 473              }
 474          }
 475      }
 476  
 477      if(!$inherited_properties)
 478      {
 479          $theme_vars = array(
 480              "theme" => "cache/themes/theme{$tid}"
 481          );
 482          $properties['logo'] = parse_theme_variables($properties['logo'], $theme_vars);
 483      }
 484      $updated_theme['stylesheets'] = $db->escape_string(serialize($stylesheets));
 485      $updated_theme['properties'] = $db->escape_string(serialize($properties));
 486  
 487      if(count($updated_theme) > 0)
 488      {
 489          $db->update_query("themes", $updated_theme, "tid='{$tid}'");
 490      }
 491  
 492      return $tid;
 493  }
 494  
 495  
 496  
 497  /**
 498   * Generates an array from an incoming CSS file.
 499   *
 500   * @param string The incoming CSS
 501   * @return array Parsed CSS file as array, false on failure
 502   */
 503  function css_to_array($css)
 504  {
 505      // Normalise line breaks
 506      $css = str_replace(array("\r\n", "\n", "\r"), "\n", $css);
 507  
 508      /**
 509       * Play with the css a  little - just to ensure we can parse it
 510       *
 511       * This essentially adds line breaks before and after each } not inside a string
 512       * so it's parsed correctly below
 513       */
 514      $stripped_css = preg_replace('#(?<!\\")\}#', "\n}\n", $css);
 515  
 516      // Fetch out classes and comments
 517      preg_match_all('#(\/\*(.|[\r\n])*?\*\/)?([a-z0-9a+\\\[\]\-\"=_:>\*\.\#\,\s\(\)\|~|@\^]+)(\s*)\{(.*?)\}\n#msi', $stripped_css, $matches, PREG_PATTERN_ORDER);
 518      $total = count($matches[1]);
 519  
 520      for($i=0; $i < $total; $i++)
 521      {
 522          $name = $description = '';
 523          $class_name = $matches[3][$i];
 524          $class_name = trim($class_name);
 525          $comments = $matches[1][$i];
 526          preg_match_all("#Name:(.*)#i", $comments, $name_match);
 527          if($name_match[count($name_match)-1][0])
 528          {
 529              $name = trim($name_match[count($name_match)-1][0]);
 530          }
 531          preg_match_all("#Description:(.*)#i", $comments, $description_match);
 532          if($description_match[count($description_match)-1][0])
 533          {
 534              $description = trim($description_match[count($description_match)-1][0]);
 535          }
 536          $class_id = md5($class_name);
 537          if($already_parsed[$class_id])
 538          {
 539              $already_parsed[$class_id]++;
 540              $class_id .= "_".$already_parsed[$class_id];
 541          }
 542          else
 543          {
 544              $already_parsed[$class_id] = 1;
 545          }
 546          $values = trim($matches[5][$i]);
 547          $values = preg_replace("#/\*(.*?)\*/#s", "", $values);
 548          $parsed_css[$class_id] = array("class_name" => $class_name, "name" => $name, "description" => $description, "values" => $values);
 549      }
 550  
 551      return $parsed_css;
 552  }
 553  
 554  function get_selectors_as_options($css, $selected_item="")
 555  {
 556      $select = "";
 557      
 558      if(!is_array($css))
 559      {
 560          $css = css_to_array($css);
 561      }
 562      
 563      $selected = false;
 564      
 565      if(is_array($css))
 566      {
 567          uasort($css, "css_selectors_sort_cmp");
 568          
 569          foreach($css as $id => $css_array)
 570          {
 571              if(!$css_array['name'])
 572              {
 573                  $css_array['name'] = $css_array['class_name'];
 574              }
 575              
 576              if($selected_item == $id || (!$selected_item && !$selected))
 577              {
 578                  $select .= "<option value=\"{$id}\" selected=\"selected\">{$css_array['name']}</option>\n";
 579                  $selected = true;
 580              }
 581              else
 582              {
 583                  $select .= "<option value=\"{$id}\">{$css_array['name']}</option>\n";
 584              }
 585          }
 586      }
 587      return $select;
 588  }
 589  
 590  function css_selectors_sort_cmp($a, $b)
 591  {
 592      if(!$a['name'])
 593      {
 594          $a['name'] = $a['class_name'];
 595      }
 596      
 597      if(!$b['name'])
 598      {
 599          $b['name'] = $b['class_name'];
 600      }
 601      return strcmp($a['name'], $b['name']);
 602  }
 603  
 604  function get_css_properties($css, $id)
 605  {
 606      if(!is_array($css))
 607      {
 608          $css = css_to_array($css);
 609      }
 610      
 611      if(!isset($css[$id]))
 612      {
 613          return false;
 614      }
 615      return parse_css_properties($css[$id]['values']);
 616  }
 617  
 618  /**
 619   * Parses CSS supported properties and returns them as an array.
 620   *
 621   * @param string Value of CSS properties from within class or selector
 622   * @return array Array of CSS properties
 623   */
 624  function parse_css_properties($values)
 625  {
 626      if(!$values)
 627      {
 628          return;
 629      }
 630      
 631      $values = explode(";", $values);
 632      foreach($values as $value)
 633      {
 634          $value = trim($value);
 635          if(!$value) continue;
 636          list($property, $css_value) = explode(":", $value, 2);
 637          $property = trim($property);
 638          switch(strtolower($property))
 639          {
 640              case "background":
 641              case "color":
 642              case "width":
 643              case "font-family":
 644              case "font-size":
 645              case "font-weight":
 646              case "font-style":
 647              case "text-decoration":
 648                  $css_bits[$property] = trim($css_value);
 649                  break;
 650              default:
 651                  $css_bits['extra'] .= "{$property}: ".trim($css_value).";\n";
 652  
 653          }
 654      }
 655      return $css_bits;
 656  }
 657  
 658  /**
 659   * Inserts an incoming string of CSS in to an already defined document. If the class ID is not found, the CSS is appended to the file.
 660   *
 661   * @param string CSS we wish to insert at this location
 662   * @param string The selector for this piece of CSS
 663   * @param string The existing CSS if we have any
 664   * @param string (Optional) The optional friendly class id value just incase the CSS is not found in the file
 665   */
 666  function insert_into_css($new_css, $selector="", $css="", $class_id="")
 667  {
 668      $new_css = str_replace(array("\r\n", "\n", "\r"), "\n", $new_css);
 669  
 670      // Build the new CSS properties list
 671      $new_css = explode("\n", $new_css);
 672      foreach($new_css as $css_line)
 673      {
 674          $generated_css .= "\t".trim($css_line)."\n";
 675      }
 676  
 677      // Parse out the CSS
 678      if($css)
 679      {
 680          $parsed_css = css_to_array($css);
 681      }
 682      
 683      if(!$class_id)
 684      {
 685          $class_id = $parsed_css[$selector]['class_name'];
 686      }
 687      
 688      // The specified class ID cannot be found, add CSS to end of file
 689      if(!$css || !$parsed_css[$selector])
 690      {
 691          return $css."{$class_id}\n{\n{$generated_css}\n}\n\n";
 692      }
 693      // Valid CSS, swap out old, swap in new
 694      else
 695      {
 696          $css = str_replace(array("\r\n", "\n", "\r"), "\n", $css);
 697          $css = preg_replace('#(?<!\\")\}#', "}\n", $css);
 698          $css = preg_replace("#\s*([a-z0-9a+\\\[\]\-\"=_:>\*\.\#\,\s\(\)\|~\^]+)(\s*)\{(\n*)#isu", "\n$1 {\n", $css);
 699          $css = preg_replace("#\s{1,}\{#", " {", $css);
 700          $existing_block = $parsed_css[$selector];
 701          
 702          $break = strrpos($selector, "_");
 703          if($break !== false)
 704          {
 705              $actual_occurance = intval(substr($selector, ($break+1)));
 706          }
 707          
 708          if(!$actual_occurance)
 709          {
 710              $actual_occurance = 1;
 711          }
 712          
 713          $occurance = 1;
 714          $pos = 0;
 715          do
 716          {
 717              $pos = strpos($css, "\n".$existing_block['class_name']." {", $pos);
 718              if($pos === false)
 719              {
 720                  break;
 721              }
 722              if($occurance == $actual_occurance)
 723              {
 724                  // This is the part we want to replace, now we need to fetch the opening & closing braces
 725                  $opening = strpos($css, "{", $pos);
 726                  $closing = strpos($css, "}", $pos);
 727                  $css = substr_replace($css, "\n".$generated_css."\n", $opening+1, $closing-$opening-1);
 728                  break;
 729              }
 730              ++$occurance;
 731              ++$pos;
 732          } while($occurance <= $actual_occurance);
 733      }
 734      $css = preg_replace("#{\n*#s", "{\n", $css);
 735      $css = preg_replace("#\s*\}\s*#", "\n}\n\n", $css);
 736      return $css;    
 737  }
 738  
 739  function copy_stylesheet_to_theme($stylesheet, $tid)
 740  {
 741      global $db;
 742      
 743      $stylesheet['tid'] = $tid;
 744      unset($stylesheet['sid']);
 745      
 746      foreach($stylesheet as $key => $value)
 747      {
 748          $stylesheet[$db->escape_string($key)] = $db->escape_string($value);
 749      }
 750      
 751      $sid = $db->insert_query("themestylesheets", $stylesheet);
 752      
 753      return $sid;
 754  }
 755  
 756  function update_theme_stylesheet_list($tid)
 757  {
 758      global $db;
 759      
 760      $stylesheets = array();
 761      
 762      $child_list = make_child_theme_list($tid);
 763      $parent_list = make_parent_theme_list($tid);
 764      
 765      if(!is_array($parent_list))
 766      {
 767          return false;
 768      }
 769      
 770      $tid_list = implode(',', $parent_list);
 771      
 772      // Get our list of stylesheets
 773      $query = $db->simple_select("themestylesheets", "sid,cachefile,attachedto,tid,lastmodified,name", "tid IN ({$tid_list})", array('order_by' => 'tid', 'order_dir' => 'desc'));
 774      while($stylesheet = $db->fetch_array($query))
 775      {
 776          if(!$stylesheets[$stylesheet['name']])
 777          {
 778              if($stylesheet['tid'] != $tid)
 779              {
 780                  $stylesheet['inherited'] = $stylesheet['tid'];
 781              }
 782              
 783              $stylesheets[$stylesheet['name']] = $stylesheet;
 784          }
 785      }
 786      
 787      foreach($stylesheets as $name => $stylesheet)
 788      {
 789          $sid = $stylesheet['sid'];
 790          $css_url = "css.php?stylesheet={$sid}";
 791          
 792          foreach($parent_list as $theme_id)
 793          {
 794              if(file_exists(MYBB_ROOT."cache/themes/theme{$theme_id}/{$stylesheet['name']}") && filemtime(MYBB_ROOT."cache/themes/theme{$theme_id}/{$stylesheet['name']}") >= $stylesheet['lastmodified'])
 795              {
 796                  $css_url = "cache/themes/theme{$theme_id}/{$stylesheet['name']}";
 797                  break;
 798              }
 799          }
 800          
 801          $attachedto = $stylesheet['attachedto'];
 802          if(!$attachedto)
 803          {
 804              $attachedto = "global";
 805          }
 806          // private.php?compose,folders|usercp.php,global|global
 807          $attachedto = explode("|", $attachedto);
 808          foreach($attachedto as $attached_file)
 809          {
 810              $attached_actions = array();
 811              if(strpos($attached_file, '?') !== false)
 812              {
 813                  $attached_file = explode('?', $attached_file);
 814                  $attached_actions = explode(",", $attached_file[1]);
 815                  $attached_file = $attached_file[0];
 816              }
 817              
 818              if(count($attached_actions) == 0)
 819              {
 820                  $attached_actions = array("global");
 821              }
 822              
 823              foreach($attached_actions as $action)
 824              {
 825                  $theme_stylesheets[$attached_file][$action][] = $css_url;
 826                  
 827                  if($stylesheet['inherited'])
 828                  {
 829                      $theme_stylesheets['inherited']["{$attached_file}_{$action}"][$css_url] = $stylesheet['inherited'];
 830                  }
 831              }
 832          }
 833      }
 834  
 835      // Now we have our list of built stylesheets, save them
 836      $updated_theme = array(
 837          "stylesheets" => $db->escape_string(serialize($theme_stylesheets))
 838      );
 839      $db->update_query("themes", $updated_theme, "tid='{$tid}'");
 840      
 841      // Do we have any children themes that need updating too?
 842      if(count($child_list) > 0)
 843      {
 844          foreach($child_list as $id)
 845          {
 846              update_theme_stylesheet_list($id);
 847          }
 848      }
 849      
 850      return true;
 851  }
 852  
 853  function make_parent_theme_list($tid)
 854  {
 855      static $themes_by_parent;
 856      
 857      $themes = array();
 858      if(!is_array($themes_by_parent))
 859      {
 860          $theme_cache = cache_themes();
 861          foreach($theme_cache as $key => $theme)
 862          {
 863              if($key == "default")
 864              {
 865                  continue;
 866              }
 867              
 868              $themes_by_parent[$theme['tid']][$theme['pid']] = $theme;
 869          }
 870      }
 871      
 872      if(!is_array($themes_by_parent[$tid]))
 873      {
 874          return false;
 875      }
 876      
 877      reset($themes_by_parent);
 878      reset($themes_by_parent[$tid]);
 879      
 880      $themes = array();
 881      
 882      foreach($themes_by_parent[$tid] as $key => $theme)
 883      {
 884          $themes[] = $theme['tid'];
 885          $parents = make_parent_theme_list($theme['pid']);
 886          
 887          if(is_array($parents))
 888          {
 889              $themes = array_merge($themes, $parents);
 890          }
 891      }
 892      
 893      return $themes;
 894  }
 895  
 896  function make_child_theme_list($tid)
 897  {
 898      static $themes_by_child;
 899      
 900      $themes = array();
 901      if(!is_array($themes_by_child))
 902      {
 903          $theme_cache = cache_themes();
 904          foreach($theme_cache as $key => $theme)
 905          {
 906              if($key == "default")
 907              {
 908                  continue;
 909              }
 910              
 911              $themes_by_child[$theme['pid']][$theme['tid']] = $theme;
 912          }
 913      }
 914      
 915      if(!is_array($themes_by_child[$tid]))
 916      {
 917          return;
 918      }
 919      
 920      $themes = array();
 921      
 922      foreach($themes_by_child[$tid] as $theme)
 923      {
 924          $themes[] = $theme['tid'];
 925          $children = make_child_theme_list($theme['tid']);
 926          
 927          if(is_array($children))
 928          {
 929              $themes = array_merge($themes, $children);
 930          }
 931      }
 932      
 933      return $themes;
 934  }
 935  
 936  function cache_themes()
 937  {
 938      global $db, $theme_cache;
 939  
 940      if(empty($theme_cache) || !is_array($theme_cache))
 941      {
 942          $query = $db->simple_select("themes", "*", "", array('order_by' => "pid, name"));
 943          while($theme = $db->fetch_array($query))
 944          {
 945              $theme['properties'] = unserialize($theme['properties']);
 946              $theme['stylesheets'] = unserialize($theme['stylesheets']);
 947              $theme_cache[$theme['tid']] = $theme;
 948              
 949              if($theme['def'] == 1)
 950              {
 951                  $theme_cache['default'] = $theme['tid'];
 952              }
 953          }
 954      }
 955      
 956      // Do we have no themes assigned as default?
 957      if(!$theme_cache['default'])
 958      {
 959          $theme_cache['default'] = 1;
 960      }
 961      
 962      return $theme_cache;
 963  }
 964  
 965  function build_theme_list($parent=0, $depth=0)
 966  {
 967      global $mybb, $db, $table, $lang, $page; // Global $table is bad, but it will have to do for now
 968      static $theme_cache;
 969  
 970      $padding = $depth*20; // Padding
 971  
 972      if(!is_array($theme_cache))
 973      {        
 974          $themes = cache_themes();
 975          $query = $db->query("
 976              SELECT style, COUNT(uid) AS users
 977              FROM ".TABLE_PREFIX."users
 978              GROUP BY style
 979          ");
 980          while($user_themes = $db->fetch_array($query))
 981          {
 982              if($user_themes['style'] == 0)
 983              {
 984                  $user_themes['style'] = $themes['default'];
 985              }
 986              
 987              if($themes[$user_themes['style']]['users'] > 0)
 988              {
 989                  $themes[$user_themes['style']]['users'] += intval($user_themes['users']);
 990              }
 991              else
 992              {
 993                  $themes[$user_themes['style']]['users'] = intval($user_themes['users']);
 994              }
 995          }
 996  
 997          // Restrucure the theme array to something we can "loop-de-loop" with
 998          foreach($themes as $key => $theme)
 999          {
1000              if($key == "default")
1001              {
1002                  continue;
1003              }
1004              
1005              $theme_cache[$theme['pid']][$theme['tid']] = $theme;
1006          }
1007          $theme_cache['num_themes'] = count($themes);
1008          unset($themes);
1009      }
1010  
1011      if(!is_array($theme_cache[$parent]))
1012      {
1013          return;
1014      }
1015  
1016      foreach($theme_cache[$parent] as $theme)
1017      {        
1018          $popup = new PopupMenu("theme_{$theme['tid']}", $lang->options);
1019          if($theme['tid'] > 1)
1020          {
1021              $popup->add_item($lang->edit_theme, "index.php?module=style-themes&amp;action=edit&amp;tid={$theme['tid']}");
1022              $theme['name'] = "<a href=\"index.php?module=style-themes&amp;action=edit&amp;tid={$theme['tid']}\">{$theme['name']}</a>";
1023              
1024              // We must have at least the master and 1 other active theme
1025              if($theme_cache['num_themes'] > 2)
1026              {
1027                  $popup->add_item($lang->delete_theme, "index.php?module=style-themes&amp;action=delete&amp;tid={$theme['tid']}&amp;my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_theme_deletion}')");
1028              }
1029              
1030              if($theme['def'] != 1)
1031              {
1032                  $popup->add_item($lang->set_as_default, "index.php?module=style-themes&amp;action=set_default&amp;tid={$theme['tid']}&amp;my_post_key={$mybb->post_code}");
1033                  $set_default = "<a href=\"index.php?module=style-themes&amp;action=set_default&amp;tid={$theme['tid']}&amp;my_post_key={$mybb->post_code}\"><img src=\"styles/{$page->style}/images/icons/make_default.gif\" alt=\"{$lang->set_as_default}\" style=\"vertical-align: middle;\" title=\"{$lang->set_as_default}\" /></a>";
1034              }
1035              else
1036              {
1037                  $set_default = "<img src=\"styles/{$page->style}/images/icons/default.gif\" alt=\"{$lang->default_theme}\" style=\"vertical-align: middle;\" title=\"{$lang->default_theme}\" />";
1038              }
1039              $popup->add_item($lang->force_on_users, "index.php?module=style-themes&amp;action=force&amp;tid={$theme['tid']}&amp;my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_theme_forced}')");
1040          }
1041          $popup->add_item($lang->export_theme, "index.php?module=style-themes&amp;action=export&amp;tid={$theme['tid']}");
1042          $table->construct_cell("<div class=\"float_right\">{$set_default}</div><div style=\"margin-left: {$padding}px;\"><strong>{$theme['name']}</strong></div>");
1043          $table->construct_cell(my_number_format($theme['users']), array("class" => "align_center"));
1044          $table->construct_cell($popup->fetch(), array("class" => "align_center"));
1045          $table->construct_row();
1046          
1047          // Fetch & build any child themes
1048          build_theme_list($theme['tid'], ++$depth);
1049      }
1050  }
1051  
1052  // returns an array which can be sent to generate_select_box()
1053  function build_theme_array($ignoretid = null, $parent=0, $depth=0)
1054  {
1055      global $mybb, $lang, $list;
1056      static $theme_cache;
1057  
1058      if(!is_array($theme_cache))
1059      {
1060          $themes = cache_themes();
1061          // Restrucure the theme array to something we can "loop-de-loop" with
1062          foreach($themes as $key => $theme)
1063          {
1064              if($key == "default")
1065              {
1066                  continue;
1067              }
1068              
1069              $theme_cache[$theme['pid']][$theme['tid']] = $theme;
1070          }
1071          unset($theme);
1072      }
1073  
1074      if(!is_array($theme_cache[$parent]) || $ignoretid === $parent)
1075      {
1076          return;
1077      }
1078  
1079      foreach($theme_cache[$parent] as $theme)
1080      {
1081          if($ignoretid === $theme['tid'])
1082          {
1083              continue;
1084          }
1085          
1086          $list[$theme['tid']] = str_repeat("--", $depth).$theme['name'];
1087          // Fetch & build any child themes
1088          build_theme_array($ignoretid, $theme['tid'], $depth+1);
1089      }
1090      
1091      if(!$parent)
1092      {
1093          return $list;
1094      }
1095  }
1096  
1097  function upgrade_css_120_to_140($css)
1098  {
1099      // Update our CSS to the new stuff in 1.4
1100      $parsed_css = css_to_array($css);
1101      
1102      if(!is_array($parsed_css))
1103      {
1104          return "";
1105      }
1106      
1107      foreach($parsed_css as $class_id => $array)
1108      {
1109          $parsed_css[$class_id]['values'] = str_replace('#eea8a1', '#ffdde0', $array['values']);
1110          $parsed_css[$class_id]['values'] = str_replace('font-family: Verdana;', 'font-family: Verdana, Arial, Sans-Serif;', $array['values']);
1111          
1112          switch($array['class_name'])
1113          {
1114              case '.bottommenu':
1115                  $parsed_css[$class_id]['values'] = str_replace('padding: 6px;', 'padding: 10px;', $array['values']);
1116                  break;
1117              case '.expcolimage':
1118                  $parsed_css[$class_id]['values'] .= "\n\tmargin-top: 2px;";
1119                  break;
1120              case '.toolbar_normal':
1121              case '.toolbar_hover':
1122              case '.toolbar_clicked':
1123              case '.pagenav':
1124              case '.pagenavbit':
1125              case '.pagenavbit a':
1126              case '.pagenavcurrent':
1127              case '.quote_header':
1128              case '.quote_body':
1129              case '.code_header':
1130              case '.code_body':
1131              case '.usercpnav':
1132              case '.usercpnav li':
1133              case '.usercpnav .pmfolders':
1134              case '.usercpnav li':
1135              case '.usercpnav li':
1136                  unset($parsed_css[$class_id]);
1137                  break;
1138              default:
1139          }        
1140      }
1141      
1142      $to_add = array(
1143          md5('.trow_selected td') => array("class_name" => '.trow_selected td', "values" => 'background: #FFFBD9;'),
1144          md5('blockquote') => array("class_name" => 'blockquote', "values" => "border: 1px solid #ccc;\n\tmargin: 0;\n\tbackground: #fff;\n\tpadding: 4px;"),
1145          md5('blockquote cite') => array("class_name" => 'blockquote cite', "values" => "font-weight: bold;\n\tborder-bottom: 1px solid #ccc;\n\tfont-style: normal;\n\tdisplay: block;\n\tmargin: 4px 0;"),
1146          md5('blockquote cite span') => array("class_name" => 'blockquote cite span', "values" => "float: right;\n\tfont-weight: normal;"),
1147          md5('.codeblock') => array("class_name" => '.codeblock', "values" => "background: #fff;\n\tborder: 1px solid #ccc;\n\tpadding: 4px;"),
1148          md5('.codeblock .title') => array("class_name" => '.codeblock .title', "values" => "border-bottom: 1px solid #ccc;\n\tfont-weight: bold;\n\tmargin: 4px 0;"),
1149          md5('.codeblock code') => array("class_name" => '.codeblock code', "values" => "overflow: auto;\n\theight: auto;\n\tmax-height: 200px;\n\tdisplay: block;\n\tfont-family: Monaco, Consolas, Courier, monospace;\n\tfont-size: 13px;"),
1150          md5('.subject_new') => array("class_name" => '.subject_new', "values" => "font-weight: bold;"),
1151          md5('.highlight') => array("class_name" => '.highlight', "values" => "background: #FFFFCC;\n\tpadding: 3px;"),
1152          md5('.pm_alert') => array("class_name" => '.pm_alert', "values" => "background: #FFF6BF;\n\tborder: 1px solid #FFD324;\n\ttext-align: center;\n\tpadding: 5px 20px;\n\tfont-size: 11px;"),
1153          md5('.red_alert') => array("class_name" => '.red_alert', "values" => "background: #FBE3E4;\n\tborder: 1px solid #A5161A;\n\tcolor: #A5161A;\n\ttext-align: center;\n\tpadding: 5px 20px;\n\tfont-size: 11px;"),
1154          md5('.high_warning') => array("class_name" => '.high_warning', "values" => "color: #CC0000;"),
1155          md5('.moderate_warning') => array("class_name" => '.moderate_warning', "values" => "color: #F3611B;"),
1156          md5('.low_warning') => array("class_name" => '.low_warning', "values" => "color: #AE5700;"),
1157          md5('div.error') => array("class_name" => 'div.error', "values" => "padding: 5px 10px;\n\tborder-top: 2px solid #FFD324;\n\tborder-bottom: 2px solid #FFD324;\n\tbackground: #FFF6BF\n\tfont-size: 12px;"),
1158          md5('.high_warning') => array("class_name" => '.high_warning', "values" => "color: #CC0000;"),
1159          md5('.moderate_warning') => array("class_name" => '.moderate_warning', "values" => "color: #F3611B;"),
1160          md5('.low_warning') => array("class_name" => '.low_warning', "values" => "color: #AE5700;"),
1161          md5('div.error') => array("class_name" => 'div.error', "values" => "padding: 5px 10px;\n\tborder-top: 2px solid #FFD324;\n\tborder-bottom: 2px solid #FFD324;\n\tbackground: #FFF6BF;\n\tfont-size: 12px;"),
1162          md5('div.error p') => array("class_name" => 'div.error p', "values" => "margin: 0;\n\tcolor: #000;\n\tfont-weight: normal;"),        
1163          md5('div.error p em') => array("class_name" => 'div.error p em', "values" => "font-style: normal;\n\tfont-weight: bold;\n\tpadding-left: 24px;\n\tdisplay: block;\n\tcolor: #C00;\n\tbackground: url({$mybb->settings['bburl']}/images/error.gif) no-repeat 0;"),
1164          md5('div.error.ul') => array("class_name" => 'div.error.ul', "values" => "margin-left: 24px;"),
1165          md5('.online') => array("class_name" => '.online', "values" => "color: #15A018;"),
1166          md5('.offline') => array("class_name" => '.offline', "values" => "color: #C7C7C7;"),
1167          md5('.pagination') => array("class_name" => '.pagination', "values" => "font-size: 11px;\n\tpadding-top: 10px;\n\tmargin-bottom: 5px;"),
1168          md5('.tfoot .pagination, .tcat .pagination') => array("class_name" => '.tfoot .pagination, .tcat .pagination', "values" => "padding-top: 0;"),
1169          md5('.pagination .pages') => array("class_name" => '.pagination .pages', "values" => "font-weight: bold;"),
1170          md5('.pagination .pagination_current, .pagination a') => array("class_name" => '.pagination .pagination_current, .pagination a', "values" => "padding: 2px 6px;\n\tmargin-bottom: 3px;"),
1171          md5('.pagination a') => array("class_name" => '.pagination a', "values" => "border: 1px solid #81A2C4;"),
1172          md5('.pagination .pagination_current') => array("class_name" => '.pagination .pagination_current', "values" => "background: #F5F5F5;\n\tborder: 1px solid #81A2C4;\n\tfont-weight: bold;"),
1173          md5('.pagination a:hover') => array("class_name" => '.pagination a:hover', "values" => "background: #F5F5F5;\n\ttext-decoration: none;"),
1174          md5('.thread_legend, .thread_legend dd') => array("class_name" => '.thread_legend, .thread_legend dd', "values" => "margin: 0;\n\tpadding: 0;"),
1175          md5('.thread_legend dd') => array("class_name" => '.thread_legend dd', "values" => "padding-bottom: 4px;\n\tmargin-right: 15px;"),
1176          md5('.thread_legend img') => array("class_name" => '.thread_legend img', "values" => "margin-right: 4px;\n\tvertical-align: bottom;"),
1177          md5('.forum_legend, .forum_legend dt, .forum_legend dd') => array("class_name" => '.forum_legend, .forum_legend dt, .forum_legend dd', "values" => "margin: 0;\n\tpadding: 0;"),
1178          md5('.forum_legend dd') => array("class_name" => '.forum_legend dd', "values" => "float: left;\n\tmargin-right: 10px;"),
1179          md5('.forum_legend dt') => array("class_name" => '.forum_legend dt', "values" => "margin-right: 10px;\n\tfloat: left;"),
1180          md5('.success_message') => array("class_name" => '.success_message', "values" => "color: #00b200;\n\tfont-weight: bold;\n\tfont-size: 10px;\n\tmargin-bottom: 10px;"),
1181          md5('.error_message') => array("class_name" => '.error_message', "values" => "color: #C00;\n\tfont-weight: bold;\n\tfont-size: 10px;\n\tmargin-bottom: 10px;"),
1182          md5('.post_body') => array("class_name" => '.post_body', "values" => "padding: 5px;"),
1183          md5('.post_content') => array("class_name" => '.post_content', "values" => "padding: 5px 10px;"),
1184          md5('.invalid_field') => array("class_name" => '.invalid_field', "values" => "border: 1px solid #f30;\n\tcolor: #f30;"),
1185          md5('.valid_field') => array("class_name" => '.valid_field', "values" => "border: 1px solid #0c0;"),
1186          md5('.validation_error') => array("class_name" => '.validation_error', "values" => "background: url(images/invalid.gif) no-repeat center left;\n\tcolor: #f30;\n\tmargin: 5px 0;\n\tpadding: 5px;\n\tfont-weight: bold;\n\tfont-size: 11px;\n\tpadding-left: 22px;"),
1187          md5('.validation_success') => array("class_name" => '.validation_success', "values" => "background: url(images/valid.gif) no-repeat center left;\n\tcolor: #00b200;\n\tmargin: 5px 0;\n\tpadding: 5px;\n\tfont-weight: bold;\n\tfont-size: 11px;\n\tpadding-left: 22px;"),
1188          md5('.validation_loading') => array("class_name" => '.validation_loading', "values" => "background: url(images/spinner.gif) no-repeat center left;\n\tcolor: #555;\n\tmargin: 5px 0;\n\tpadding: 5px;\n\tfont-weight: bold;\n\tfont-size: 11px;\n\tpadding-left: 22px;"),
1189      );
1190      
1191      foreach($to_add as $class_id => $array)
1192      {
1193          if($already_parsed[$class_id])
1194          {
1195              $already_parsed[$class_id]++;
1196              $class_id .= "_".$already_parsed[$class_id];
1197          }
1198          else
1199          {
1200              $already_parsed[$class_id] = 1;
1201          }
1202          
1203          $array['name'] = "";
1204          $array['description'] = "";
1205          
1206          $parsed_css[$class_id] = $array;
1207      }
1208      
1209      $css = "";
1210      foreach($parsed_css as $class_id => $array)
1211      {
1212          if($array['name'] || $array['description'])
1213          {
1214              $theme['css'] .= "/* ";
1215              if($array['name'])
1216              {
1217                  $array['css'] .= "Name: {$array['name']}";
1218                  
1219                  if($array['description'])
1220                  {
1221                      $array['css'] .= "\n";
1222                  }
1223              }
1224              
1225              if($array['description'])
1226              {
1227                  $array['css'] .= "Description: {$array['description']}";
1228              }
1229              
1230              $array['css'] .= " */\n";
1231          }
1232          
1233          $css .= "{$array['class_name']} {\n\t{$array['values']}\n}\n";
1234      }
1235          
1236      return $css;
1237  }
1238  ?>


Generated: Sun Dec 11 14:16:27 2011 Cross-referenced by PHPXref 0.7.1