| [ Index ] |
PHP Cross Reference of MyBB 1.6.5 |
[Summary view] [Print] [Text view]
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&action=edit&tid={$theme['tid']}"); 1022 $theme['name'] = "<a href=\"index.php?module=style-themes&action=edit&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&action=delete&tid={$theme['tid']}&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&action=set_default&tid={$theme['tid']}&my_post_key={$mybb->post_code}"); 1033 $set_default = "<a href=\"index.php?module=style-themes&action=set_default&tid={$theme['tid']}&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&action=force&tid={$theme['tid']}&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&action=export&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 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Sun Dec 11 14:16:27 2011 | Cross-referenced by PHPXref 0.7.1 |