b2evolution PHP Cross Reference Blogging Systems

Source: /inc/collections/model/_blog.class.php - 2926 lines - 93333 bytes - Summary - Text - Print

Description: This file implements the Blog class. This file is part of the evoCore framework - {@link http://evocore.net/} See also {@link http://sourceforge.net/projects/evocms/}.

   1  <?php
   2  /**
   3   * This file implements the Blog class.
   4   *
   5   * This file is part of the evoCore framework - {@link http://evocore.net/}
   6   * See also {@link http://sourceforge.net/projects/evocms/}.
   7   *
   8   * @copyright (c)2003-2014 by Francois Planque - {@link http://fplanque.com/}
   9   * Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}.
  10   * Parts of this file are copyright (c)2005 by Jason Edgecombe.
  11   *
  12   * {@internal License choice
  13   * - If you have received this file as part of a package, please find the license.txt file in
  14   *   the same folder or the closest folder above for complete license terms.
  15   * - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/)
  16   *   then you must choose one of the following licenses before using the file:
  17   *   - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php
  18   *   - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php
  19   * }}
  20   *
  21   * {@internal Open Source relicensing agreement:
  22   * Daniel HAHLER grants Francois PLANQUE the right to license
  23   * Daniel HAHLER's contributions to this file and the b2evolution project
  24   * under any OSI approved OSS license (http://www.opensource.org/licenses/).
  25   *
  26   * Jason EDGECOMBE grants Francois PLANQUE the right to license
  27   * Jason EDGECOMBE's contributions to this file and the b2evolution project
  28   * under any OSI approved OSS license (http://www.opensource.org/licenses/).
  29   * }}
  30   *
  31   * @package evocore
  32   *
  33   * @version $Id: _blog.class.php 6136 2014-03-08 07:59:48Z manuel $
  34   */
  35  if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
  36  
  37  load_class( '_core/model/dataobjects/_dataobject.class.php', 'DataObject' );
  38  
  39  /**
  40   * Blog
  41   *
  42   * Blog object with params
  43   *
  44   * @package evocore
  45   */
  46  class Blog extends DataObject
  47  {
  48      /**
  49       * Short name for use in navigation menus
  50       * @var string
  51       */
  52      var $shortname;
  53  
  54      /**
  55       * Complete name
  56       * @var string
  57       */
  58      var $name;
  59  
  60      /**
  61       * Tagline to be displayed on template
  62       * @var string
  63       */
  64      var $tagline;
  65  
  66      var $shortdesc; // description
  67      var $longdesc;
  68  
  69      /**
  70       * @var integer
  71       */
  72      var $owner_user_ID;
  73  
  74      /**
  75       * Lazy filled
  76       * @var User
  77       * @see get_owner_User()
  78       * @access protected
  79       */
  80      var $owner_User = NULL;
  81  
  82      var $advanced_perms = 0;
  83  
  84      var $locale;
  85      var $access_type;
  86  
  87      /*
  88       * ?> TODO: we should have an extra DB column that either defines type of blog_siteurl
  89       * OR split blog_siteurl into blog_siteurl_abs and blog_siteurl_rel (where blog_siteurl_rel could be "blog_sitepath")
  90       */
  91      var $siteurl;
  92      var $stub;     // stub file (can be empty/virtual)
  93      var $urlname;  // used to identify blog in URLs
  94      var $links_blog_ID = 0;    // DEPRECATED
  95      var $notes;
  96      var $keywords;
  97      var $allowtrackbacks = 0;
  98      var $allowblogcss = 0;
  99      var $allowusercss = 0;
 100      var $in_bloglist = 1;
 101      var $UID;
 102      var $media_location = 'default';
 103      var $media_subdir = '';
 104      var $media_fullpath = '';
 105      var $media_url = '';
 106  
 107  
 108      /**
 109       * The URL to the basepath of that blog.
 110       * This is supposed to be the same as $baseurl but localized to the domain of the blog/
 111       *
 112       * Lazy filled by get_basepath_url()
 113       *
 114       * @var string
 115       */
 116      var $basepath_url;
 117  
 118      /**
 119       * Additional settings for the collection.  lazy filled.
 120        *
 121       * @see Blog::get_setting()
 122       * @see Blog::set_setting()
 123       * @see Blog::load_CollectionSettings()
 124       * Any non vital params should go into there (this includes many of the above).
 125       *
 126       * @var CollectionSettings
 127       */
 128      var $CollectionSettings;
 129  
 130  
 131      /**
 132       * Lazy filled
 133       *
 134       * @var integer
 135       */
 136      var $default_cat_ID;
 137  
 138      /**
 139       * @var string Type of blog ( 'std', 'photo', 'group', 'forum', 'manual' )
 140       */
 141      var $type;
 142  
 143  
 144      /**
 145       * Constructor
 146       *
 147       * @param object DB row
 148       */
 149  	function Blog( $db_row = NULL )
 150      {
 151          global $Timer;
 152  
 153          $Timer->start( 'Blog constructor' );
 154  
 155          // Call parent constructor:
 156          parent::DataObject( 'T_blogs', 'blog_', 'blog_ID' );
 157  
 158          $this->delete_restrictions = array(
 159                  array( 'table'=>'T_categories', 'fk'=>'cat_blog_ID', 'msg'=>T_('%d related categories') ),
 160                  array( 'table'=>'T_files', 'fk'=>'file_root_ID', 'and_condition' => 'file_root_type = "collection"', 'msg'=>T_('%d files in this blog file root') ),
 161              );
 162  
 163          $this->delete_cascades = array(
 164                  array( 'table'=>'T_coll_settings', 'fk'=>'cset_coll_ID', 'msg'=>T_('%d blog settings') ),
 165                  array( 'table'=>'T_coll_user_perms', 'fk'=>'bloguser_blog_ID', 'msg'=>T_('%d user permission definitions') ),
 166                  array( 'table'=>'T_coll_group_perms', 'fk'=>'bloggroup_blog_ID', 'msg'=>T_('%d group permission definitions') ),
 167                  array( 'table'=>'T_subscriptions', 'fk'=>'sub_coll_ID', 'msg'=>T_('%d subscriptions') ),
 168                  array( 'table'=>'T_widget', 'fk'=>'wi_coll_ID', 'msg'=>T_('%d widgets') ),
 169                  array( 'table'=>'T_hitlog', 'fk'=>'hit_blog_ID', 'msg'=>T_('%d hits') ),
 170              );
 171  
 172          if( $db_row == NULL )
 173          {
 174              global $default_locale;
 175              // echo 'Creating blank blog';
 176              $this->owner_user_ID = 1; // DB default
 177              $this->set( 'locale', $default_locale );
 178              $this->set( 'access_type', 'extrapath' );
 179          }
 180          else
 181          {
 182              $this->ID = $db_row->blog_ID;
 183              $this->shortname = $db_row->blog_shortname;
 184              $this->name = $db_row->blog_name;
 185              $this->owner_user_ID = $db_row->blog_owner_user_ID;
 186              $this->advanced_perms = $db_row->blog_advanced_perms;
 187              $this->tagline = $db_row->blog_tagline;
 188              $this->shortdesc = $db_row->blog_description;    // description
 189              $this->longdesc = $db_row->blog_longdesc;
 190              $this->locale = $db_row->blog_locale;
 191              $this->access_type = $db_row->blog_access_type;
 192              $this->siteurl = $db_row->blog_siteurl;
 193              $this->urlname = $db_row->blog_urlname;
 194              $this->links_blog_ID = $db_row->blog_links_blog_ID; // DEPRECATED
 195              $this->notes = $db_row->blog_notes;
 196              $this->keywords = $db_row->blog_keywords;
 197              $this->allowtrackbacks = $db_row->blog_allowtrackbacks;
 198              $this->allowblogcss = $db_row->blog_allowblogcss;
 199              $this->allowusercss = $db_row->blog_allowusercss;
 200              $this->in_bloglist = $db_row->blog_in_bloglist;
 201              $this->media_location = $db_row->blog_media_location;
 202              $this->media_subdir = $db_row->blog_media_subdir;
 203              $this->media_fullpath = $db_row->blog_media_fullpath;
 204              $this->media_url = $db_row->blog_media_url;
 205              $this->UID = $db_row->blog_UID;
 206              $this->type = $db_row->blog_type;
 207          }
 208  
 209          $Timer->pause( 'Blog constructor' );
 210      }
 211  
 212  
 213      /**
 214       * @param string
 215       */
 216  	function init_by_kind( $kind, $name = NULL, $shortname = NULL, $urlname = NULL )
 217      {
 218          switch( $kind )
 219          {
 220              case 'photo':
 221                  $this->set( 'type', 'photo' );
 222                  $this->set( 'name', empty($name) ? T_('My photoblog') : $name );
 223                  $this->set( 'shortname', empty($shortname) ? T_('Photoblog') : $shortname );
 224                  $this->set( 'urlname', empty($urlname) ? 'photo' : $urlname );
 225                  $this->set_setting( 'posts_per_page', 1 );
 226                  $this->set_setting( 'archive_mode', 'postbypost' );
 227                  break;
 228  
 229              case 'group':
 230                  $this->set( 'type', 'group' );
 231                  $this->set( 'name', empty($name) ? T_('Our blog') : $name );
 232                  $this->set( 'shortname', empty($shortname) ? T_('Group') : $shortname );
 233                  $this->set( 'urlname', empty($urlname) ? 'group' : $urlname );
 234                  $this->set_setting( 'use_workflow', 1 );
 235                  break;
 236  
 237              case 'forum':
 238                  $this->set( 'type', 'forum' );
 239                  $this->set( 'name', empty($name) ? T_('My forum') : $name );
 240                  $this->set( 'shortname', empty($shortname) ? T_('Forum') : $shortname );
 241                  $this->set( 'urlname', empty($urlname) ? 'forum' : $urlname );
 242                  $this->set( 'advanced_perms', 1 );
 243                  $this->set_setting( 'post_navigation', 'same_category' );
 244                  $this->set_setting( 'allow_comments', 'registered' );
 245                  $this->set_setting( 'in_skin_editing', '1' );
 246                  $this->set_setting( 'posts_per_page', 30 );
 247                  $this->set_setting( 'allow_html_post', 0 );
 248                  $this->set_setting( 'allow_html_comment', 0 );
 249                  $this->set_setting( 'orderby', 'last_touched_ts' );
 250                  $this->set_setting( 'orderdir', 'DESC' );
 251                  $this->set_setting( 'enable_goto_blog', 'post' );
 252                  break;
 253  
 254              case 'manual':
 255                  $this->set( 'type', 'manual' );
 256                  $this->set( 'name', empty($name) ? T_('Manual') : $name );
 257                  $this->set( 'shortname', empty($shortname) ? T_('Manual') : $shortname );
 258                  $this->set( 'urlname', empty($urlname) ? 'manual' : $urlname );
 259                  $this->set_setting( 'post_navigation', 'same_category' );
 260                  $this->set_setting( 'single_links', 'chapters' );
 261                  $this->set_setting( 'enable_goto_blog', 'post' );
 262                  break;
 263  
 264              case 'std':
 265              default:
 266                  $this->set( 'type', 'std' );
 267                  $this->set( 'name', empty($name) ? T_('My weblog') : $name );
 268                  $this->set( 'shortname', empty($shortname) ? T_('Blog') : $shortname );
 269                  $this->set( 'urlname', empty($urlname) ? 'blog' : $urlname );
 270                  break;
 271          }
 272  
 273          if( empty($name) && empty($shortname) && empty($urlname) )
 274          {    // Not in installation mode, init custom collection kinds.
 275              global $Plugins;
 276  
 277              // Defines blog settings by its kind.
 278              $Plugins->trigger_event( 'InitCollectionKinds', array(
 279                              'Blog' => & $this,
 280                              'kind' => & $kind,
 281                          ) );
 282          }
 283      }
 284  
 285  
 286      /**
 287       * Load data from Request form fields.
 288       *
 289       * @param array groups of params to load
 290       * @return boolean true if loaded data seems valid.
 291       */
 292  	function load_from_Request( $groups = array() )
 293      {
 294          global $Messages, $default_locale, $DB;
 295  
 296          /**
 297           * @var User
 298           */
 299          global $current_User;
 300  
 301          // Load collection settings and clear update cascade array
 302          $this->load_CollectionSettings();
 303          $this->CollectionSettings->clear_update_cascade();
 304  
 305          if( param( 'blog_name', 'string', NULL ) !== NULL )
 306          { // General params:
 307              $this->set_from_Request( 'name' );
 308              $this->set( 'shortname',     param( 'blog_shortname',     'string', true ) );
 309              $this->set( 'locale',        param( 'blog_locale',        'string', $default_locale ) );
 310          }
 311  
 312  
 313          if( param( 'archive_links',   'string', NULL ) !== NULL )
 314          { // Archive link type:
 315              $this->set_setting( 'archive_links', get_param( 'archive_links' ) );
 316              $this->set_setting( 'archive_posts_per_page', param( 'archive_posts_per_page', 'integer', NULL ), true );
 317          }
 318  
 319          if( param( 'chapter_links',   'string', NULL ) !== NULL )
 320          { // Chapter link type:
 321              $this->set_setting( 'chapter_links', get_param( 'chapter_links' ) );
 322          }
 323  
 324  
 325          if( param( 'category_prefix', 'string', NULL) !== NULL )
 326          {
 327              $category_prefix = get_param( 'category_prefix' );
 328              if( ! preg_match( '|^([A-Za-z0-9\-_]+(/[A-Za-z0-9\-_]+)*)?$|', $category_prefix) )
 329              {
 330                  param_error( 'category_prefix', T_('Invalid category prefix.') );
 331              }
 332              $this->set_setting( 'category_prefix', $category_prefix);
 333          }
 334  
 335          if( param( 'atom_redirect', 'string', NULL ) !== NULL )
 336          {
 337              param_check_url( 'atom_redirect', 'commenting' );
 338              $this->set_setting( 'atom_redirect', get_param( 'atom_redirect' ) );
 339  
 340              param( 'rss2_redirect', 'string', NULL );
 341              param_check_url( 'rss2_redirect', 'commenting' );
 342              $this->set_setting( 'rss2_redirect', get_param( 'rss2_redirect' ) );
 343          }
 344  
 345          if( param( 'image_size', 'string', NULL ) !== NULL )
 346          {
 347              $this->set_setting( 'image_size', get_param( 'image_size' ));
 348          }
 349  
 350          if( param( 'tag_links',   'string', NULL ) !== NULL )
 351          { // Tag page link type:
 352              $this->set_setting( 'tag_links', get_param( 'tag_links' ) );
 353          }
 354  
 355          if( param( 'tag_prefix', 'string', NULL) !== NULL )
 356          {
 357              $tag_prefix = get_param( 'tag_prefix' );
 358              if( ! preg_match( '|^([A-Za-z0-9\-_]+(/[A-Za-z0-9\-_]+)*)?$|', $tag_prefix) )
 359              {
 360                  param_error( 'tag_prefix', T_('Invalid tag prefix.') );
 361              }
 362              $this->set_setting( 'tag_prefix', $tag_prefix);
 363          }
 364  
 365          // Default to "tag", if "prefix-only" is used, but no tag_prefix was provided.
 366          if( get_param('tag_links') == 'prefix-only' && ! strlen(param( 'tag_prefix', 'string', NULL)) )
 367          {
 368              $this->set_setting( 'tag_prefix', 'tag' );
 369          }
 370  
 371          // Use rel="tag" attribute? (checkbox)
 372          $this->set_setting( 'tag_rel_attib', param('tag_rel_attib', 'integer', 0) );
 373  
 374  
 375          if( param( 'chapter_content', 'string', NULL ) !== NULL )
 376          { // What kind of content on chapter pages?
 377              $this->set_setting( 'chapter_content', get_param( 'chapter_content' ) );
 378          }
 379          if( param( 'tag_content', 'string', NULL ) !== NULL )
 380          { // What kind of content on tags pages?
 381              $this->set_setting( 'tag_content', get_param( 'tag_content' ) );
 382          }
 383          if( param( 'archive_content', 'string', NULL ) !== NULL )
 384          { // What kind of content on archive pages?
 385              $this->set_setting( 'archive_content', get_param( 'archive_content' ) );
 386          }
 387          if( param( 'filtered_content', 'string', NULL ) !== NULL )
 388          { // What kind of content on filtered pages?
 389              $this->set_setting( 'filtered_content', get_param( 'filtered_content' ) );
 390          }
 391          if( param( 'main_content', 'string', NULL ) !== NULL )
 392          { // What kind of content on main pages?
 393              $this->set_setting( 'main_content', get_param( 'main_content' ) );
 394          }
 395  
 396          // Chapter posts per page:
 397          $this->set_setting( 'chapter_posts_per_page', param( 'chapter_posts_per_page', 'integer', NULL ), true );
 398          // Tag posts per page:
 399          $this->set_setting( 'tag_posts_per_page', param( 'tag_posts_per_page', 'integer', NULL ), true );
 400  
 401          if( param( 'single_links', 'string', NULL ) !== NULL )
 402          { // Single post link type:
 403              $this->set_setting( 'single_links', get_param( 'single_links' ) );
 404          }
 405  
 406          if( param( 'slug_limit', 'integer', NULL ) !== NULL )
 407          { // Limit slug length:
 408              $this->set_setting( 'slug_limit', get_param( 'slug_limit' ) );
 409          }
 410  
 411          if( param( 'normal_skin_ID', 'integer', NULL ) !== NULL )
 412          {    // Default blog:
 413              $this->set_setting( 'normal_skin_ID', get_param( 'normal_skin_ID' ) );
 414          }
 415  
 416          if( param( 'mobile_skin_ID', 'integer', NULL ) !== NULL )
 417          {    // Default blog:
 418              $this->set_setting( 'mobile_skin_ID', get_param( 'mobile_skin_ID' ) );
 419          }
 420  
 421          if( param( 'tablet_skin_ID', 'integer', NULL ) !== NULL )
 422          {    // Default blog:
 423              $this->set_setting( 'tablet_skin_ID', get_param( 'tablet_skin_ID' ) );
 424          }
 425  
 426          if( param( 'archives_sort_order', 'string', NULL ) !== NULL )
 427          {
 428              $this->set_setting( 'archives_sort_order', param( 'archives_sort_order', 'string', false ) );
 429          }
 430  
 431          if( param( 'feed_content', 'string', NULL ) !== NULL )
 432          { // How much content in feeds?
 433              $this->set_setting( 'feed_content', get_param( 'feed_content' ) );
 434  
 435              param_integer_range( 'posts_per_feed', 1, 9999, T_('Items per feed must be between %d and %d.') );
 436              $this->set_setting( 'posts_per_feed', get_param( 'posts_per_feed' ) );
 437          }
 438  
 439          if( param( 'comment_feed_content', 'string', NULL ) !== NULL )
 440          { // How much content in comment feeds?
 441              $this->set_setting( 'comment_feed_content', get_param( 'comment_feed_content' ) );
 442  
 443              param_integer_range( 'comments_per_feed', 1, 9999, T_('Comments per feed must be between %d and %d.') );
 444              $this->set_setting( 'comments_per_feed', get_param( 'comments_per_feed' ) );
 445          }
 446  
 447          if( param( 'require_title', 'string', NULL ) !== NULL )
 448          { // Title for items required?
 449              $this->set_setting( 'require_title', get_param( 'require_title' ) );
 450          }
 451  
 452          if( param( 'blog_description', 'string', NULL ) !== NULL )
 453          {    // Description:
 454              $this->set_from_Request( 'shortdesc', 'blog_description' );
 455          }
 456  
 457          if( param( 'blog_keywords', 'string', NULL ) !== NULL )
 458          {    // Keywords:
 459              $this->set_from_Request( 'keywords' );
 460          }
 461  
 462          if( param( 'blog_tagline', 'html', NULL ) !== NULL )
 463          {    // HTML tagline:
 464              param_check_html( 'blog_tagline', T_('Invalid tagline') );
 465              $this->set( 'tagline', get_param( 'blog_tagline' ) );
 466          }
 467          if( param( 'blog_longdesc', 'html', NULL ) !== NULL )
 468          {    // HTML long description:
 469              param_check_html( 'blog_longdesc', T_('Invalid long description') );
 470              $this->set( 'longdesc', get_param( 'blog_longdesc' ) );
 471          }
 472  
 473          if( param( 'blog_footer_text', 'html', NULL ) !== NULL )
 474          { // Blog footer:
 475              param_check_html( 'blog_footer_text', T_('Invalid blog footer') );
 476              $this->set_setting( 'blog_footer_text', get_param( 'blog_footer_text' ) );
 477          }
 478          if( param( 'single_item_footer_text', 'html', NULL ) !== NULL )
 479          { // Blog footer:
 480              param_check_html( 'single_item_footer_text', T_('Invalid single post footer') );
 481              $this->set_setting( 'single_item_footer_text', get_param( 'single_item_footer_text' ) );
 482          }
 483          if( param( 'xml_item_footer_text', 'html', NULL ) !== NULL )
 484          { // Blog footer:
 485              param_check_html( 'xml_item_footer_text', T_('Invalid RSS footer') );
 486              $this->set_setting( 'xml_item_footer_text', get_param( 'xml_item_footer_text' ) );
 487          }
 488          if( param( 'blog_notes', 'html', NULL ) !== NULL )
 489          {    // HTML notes:
 490              param_check_html( 'blog_notes', T_('Invalid Blog Notes') );
 491              $this->set( 'notes', get_param( 'blog_notes' ) );
 492  
 493              param_integer_range( 'max_footer_credits', 0, 3, T_('Max credits must be between %d and %d.') );
 494              $this->set_setting( 'max_footer_credits', get_param( 'max_footer_credits' ) );
 495          }
 496  
 497  
 498          if( in_array( 'pings', $groups ) )
 499          { // we want to load the ping checkboxes:
 500              $blog_ping_plugins = param( 'blog_ping_plugins', 'array/string', array() );
 501              $blog_ping_plugins = array_unique($blog_ping_plugins);
 502              $this->set_setting('ping_plugins', implode(',', $blog_ping_plugins));
 503          }
 504  
 505          if( in_array( 'authors', $groups ) )
 506          { // we want to load the multiple authors params
 507              $this->set( 'advanced_perms',  param( 'advanced_perms', 'integer', 0 ) );
 508              $this->set_setting( 'use_workflow',  param( 'blog_use_workflow', 'integer', 0 ) );
 509          }
 510  
 511          if( in_array( 'features', $groups ) )
 512          { // we want to load the workflow checkboxes:
 513              $this->set_setting( 'allow_html_post', param( 'allow_html_post', 'integer', 0 ) );
 514  
 515              $this->set_setting( 'enable_goto_blog', param( 'enable_goto_blog', 'string', NULL ) );
 516  
 517              $this->set_setting( 'editing_goto_blog', param( 'editing_goto_blog', 'string', NULL ) );
 518  
 519              $this->set_setting( 'default_post_status', param( 'default_post_status', 'string', NULL ) );
 520  
 521              $this->set_setting( 'post_categories', param( 'post_categories', 'string', NULL ) );
 522  
 523              $this->set_setting( 'post_navigation', param( 'post_navigation', 'string', NULL ) );
 524  
 525              // Show x days or x posts?:
 526              $this->set_setting( 'what_to_show', param( 'what_to_show', 'string', '' ) );
 527  
 528              param_integer_range( 'posts_per_page', 1, 9999, T_('Items/days per page must be between %d and %d.') );
 529              $this->set_setting( 'posts_per_page', get_param( 'posts_per_page' ) );
 530  
 531              $this->set_setting( 'orderby', param( 'orderby', 'string', true ) );
 532              $this->set_setting( 'orderdir', param( 'orderdir', 'string', true ) );
 533  
 534              // Time frame
 535              $this->set_setting( 'timestamp_min', param( 'timestamp_min', 'string', '' ) );
 536              $this->set_setting( 'timestamp_min_duration', param_duration( 'timestamp_min_duration' ) );
 537              $this->set_setting( 'timestamp_max', param( 'timestamp_max', 'string', '' ) );
 538              $this->set_setting( 'timestamp_max_duration', param_duration( 'timestamp_max_duration' ) );
 539  
 540              // Location
 541              $location_country = param( 'location_country', 'string', 'hidden' );
 542              $location_region = param( 'location_region', 'string', 'hidden' );
 543              $location_subregion = param( 'location_subregion', 'string', 'hidden' );
 544              $location_city = param( 'location_city', 'string', 'hidden' );
 545  
 546              if( $location_city == 'required' )
 547              {    // If city is required - all location fields also are required
 548                  $location_country = $location_region = $location_subregion = 'required';
 549              }
 550              else if( $location_subregion == 'required' )
 551              {    // If subregion is required - country & region fields also are required
 552                  $location_country = $location_region = 'required';
 553              }
 554              else if( $location_region == 'required' )
 555              {    // If region is required - country field also is required
 556                  $location_country = 'required';
 557              }
 558  
 559              $this->set_setting( 'location_country', $location_country );
 560              $this->set_setting( 'location_region', $location_region );
 561              $this->set_setting( 'location_subregion', $location_subregion );
 562              $this->set_setting( 'location_city', $location_city );
 563  
 564              // Set to show Latitude & Longitude params for this blog items
 565              $this->set_setting( 'show_location_coordinates', param( 'show_location_coordinates', 'integer', 0 ) );
 566  
 567              // Load custom double & varchar fields
 568              $custom_field_names = array();
 569              $this->load_custom_fields( 'double', $update_cascade_query, $custom_field_names );
 570              $this->load_custom_fields( 'varchar', $update_cascade_query, $custom_field_names );
 571              if( !empty( $update_cascade_query ) )
 572              { // Some custom fields were deleted and these fields must be deleted from the item settings table also. Add required query.
 573                  $this->CollectionSettings->add_update_cascade( $update_cascade_query );
 574              }
 575  
 576              // call modules update_collection_features on this blog
 577              modules_call_method( 'update_collection_features', array( 'edited_Blog' => & $this ) );
 578          }
 579  
 580          if( in_array( 'comments', $groups ) )
 581          { // we want to load the workflow checkboxes:
 582              // load moderation statuses
 583              $moderation_statuses = get_visibility_statuses( 'moderation' );
 584              $blog_moderation_statuses = array();
 585              foreach( $moderation_statuses as $status )
 586              {
 587                  if( param( 'notif_'.$status, 'integer', 0 ) )
 588                  {
 589                      $blog_moderation_statuses[] = $status;
 590                  }
 591              }
 592              $this->set_setting( 'moderation_statuses', implode( ',', $blog_moderation_statuses ) );
 593  
 594              $this->set_setting( 'comment_quick_moderation',  param( 'comment_quick_moderation', 'string', 'expire' ) );
 595              $this->set_setting( 'allow_item_subscriptions', param( 'allow_item_subscriptions', 'integer', 0 ) );
 596              $this->set_setting( 'comments_detect_email', param( 'comments_detect_email', 'integer', 0 ) );
 597              $this->set_setting( 'comments_register', param( 'comments_register', 'integer', 0 ) );
 598          }
 599  
 600          if( in_array( 'other', $groups ) )
 601          { // we want to load the workflow checkboxes:
 602              $this->set_setting( 'enable_sitemaps', param( 'enable_sitemaps', 'integer', 0 ) );
 603  
 604              $this->set_setting( 'allow_subscriptions', param( 'allow_subscriptions', 'integer', 0 ) );
 605              $this->set_setting( 'allow_item_subscriptions', param( 'allow_item_subscriptions', 'integer', 0 ) );
 606  
 607              // Public blog list
 608              $this->set( 'in_bloglist', param( 'blog_in_bloglist',   'integer', 0 ) );
 609  
 610              $this->set_setting( 'image_size_user_list', param( 'image_size_user_list', 'string' ) );
 611              $this->set_setting( 'image_size_messaging', param( 'image_size_messaging', 'string' ) );
 612  
 613              $this->set_setting( 'archive_mode', param( 'archive_mode', 'string', true ) );
 614          }
 615  
 616          if( param( 'allow_comments', 'string', NULL ) !== NULL )
 617          { // Feedback options:
 618              $this->set_setting( 'allow_comments', param( 'allow_comments', 'string', 'any' ) );
 619              $this->set_setting( 'allow_view_comments', param( 'allow_view_comments', 'string', 'any' ) );
 620              $new_feedback_status = param( 'new_feedback_status', 'string', 'draft' );
 621              if( $new_feedback_status != $this->get_setting( 'new_feedback_status' ) && ( $new_feedback_status != 'published' || $current_User->check_perm( 'blog_admin', 'edit', false, $this->ID ) ) )
 622              { // Only admin can set this setting to 'Public'
 623                  $this->set_setting( 'new_feedback_status', $new_feedback_status );
 624              }
 625              $this->set_setting( 'disable_comments_bypost', param( 'disable_comments_bypost', 'string', '0' ) );
 626              $this->set_setting( 'allow_anon_url', param( 'allow_anon_url', 'string', '0' ) );
 627              $this->set_setting( 'allow_html_comment', param( 'allow_html_comment', 'string', '0' ) );
 628              $this->set_setting( 'allow_attachments', param( 'allow_attachments', 'string', 'registered' ) );
 629              $this->set_setting( 'max_attachments', param( 'max_attachments', 'integer', '' ) );
 630              $this->set_setting( 'allow_rating_items', param( 'allow_rating_items', 'string', 'never' ) );
 631              $this->set_setting( 'rating_question', param( 'rating_question', 'text' ) );
 632              $this->set_setting( 'allow_rating_comment_helpfulness', param( 'allow_rating_comment_helpfulness', 'string', '0' ) );
 633              $blog_allowtrackbacks = param( 'blog_allowtrackbacks', 'integer', 0 );
 634              if( $blog_allowtrackbacks != $this->get( 'allowtrackbacks' ) && ( $blog_allowtrackbacks == 0 || $current_User->check_perm( 'blog_admin', 'edit', false, $this->ID ) ) )
 635              { // Only admin can turn ON this setting
 636                  $this->set( 'allowtrackbacks', $blog_allowtrackbacks );
 637              }
 638              $this->set_setting( 'comments_orderdir', param( 'comments_orderdir', '/^(?:ASC|DESC)$/', 'ASC' ) );
 639  
 640              // call modules update_collection_comments on this blog
 641              modules_call_method( 'update_collection_comments', array( 'edited_Blog' => & $this ) );
 642  
 643              $threaded_comments = param( 'threaded_comments', 'integer', 0 );
 644              $this->set_setting( 'threaded_comments', $threaded_comments );
 645              $this->set_setting( 'paged_comments', $threaded_comments ? 0 : param( 'paged_comments', 'integer', 0 ) );
 646              param_integer_range( 'comments_per_page', 1, 9999, T_('Comments per page must be between %d and %d.') );
 647              $this->set_setting( 'comments_per_page', get_param( 'comments_per_page' ) );
 648              $this->set_setting( 'comments_avatars', param( 'comments_avatars', 'integer', 0 ) );
 649              $this->set_setting( 'comments_latest', param( 'comments_latest', 'integer', 0 ) );
 650          }
 651  
 652  
 653          if( in_array( 'seo', $groups ) )
 654          { // we want to load the workflow checkboxes:
 655              $this->set_setting( 'canonical_homepage', param( 'canonical_homepage', 'integer', 0 ) );
 656              $this->set_setting( 'relcanonical_homepage', param( 'relcanonical_homepage', 'integer', 0 ) );
 657              $this->set_setting( 'canonical_item_urls', param( 'canonical_item_urls', 'integer', 0 ) );
 658              $this->set_setting( 'relcanonical_item_urls', param( 'relcanonical_item_urls', 'integer', 0 ) );
 659              $this->set_setting( 'canonical_archive_urls', param( 'canonical_archive_urls', 'integer', 0 ) );
 660              $this->set_setting( 'relcanonical_archive_urls', param( 'relcanonical_archive_urls', 'integer', 0 ) );
 661              $this->set_setting( 'canonical_cat_urls', param( 'canonical_cat_urls', 'integer', 0 ) );
 662              $this->set_setting( 'relcanonical_cat_urls', param( 'relcanonical_cat_urls', 'integer', 0 ) );
 663              $this->set_setting( 'canonical_tag_urls', param( 'canonical_tag_urls', 'integer', 0 ) );
 664              $this->set_setting( 'relcanonical_tag_urls', param( 'relcanonical_tag_urls', 'integer', 0 ) );
 665              $this->set_setting( 'default_noindex', param( 'default_noindex', 'integer', 0 ) );
 666              $this->set_setting( 'paged_noindex', param( 'paged_noindex', 'integer', 0 ) );
 667              $this->set_setting( 'paged_nofollowto', param( 'paged_nofollowto', 'integer', 0 ) );
 668              $this->set_setting( 'archive_noindex', param( 'archive_noindex', 'integer', 0 ) );
 669              $this->set_setting( 'archive_nofollowto', param( 'archive_nofollowto', 'integer', 0 ) );
 670              $this->set_setting( 'chapter_noindex', param( 'chapter_noindex', 'integer', 0 ) );
 671              $this->set_setting( 'tag_noindex', param( 'tag_noindex', 'integer', 0 ) );
 672              $this->set_setting( 'filtered_noindex', param( 'filtered_noindex', 'integer', 0 ) );
 673              $this->set_setting( 'arcdir_noindex', param( 'arcdir_noindex', 'integer', 0 ) );
 674              $this->set_setting( 'catdir_noindex', param( 'catdir_noindex', 'integer', 0 ) );
 675              $this->set_setting( 'feedback-popup_noindex', param( 'feedback-popup_noindex', 'integer', 0 ) );
 676              $this->set_setting( 'msgform_noindex', param( 'msgform_noindex', 'integer', 0 ) );
 677              $this->set_setting( 'special_noindex', param( 'special_noindex', 'integer', 0 ) );
 678              $this->set_setting( 'title_link_type', param( 'title_link_type', 'string', '' ) );
 679              $this->set_setting( 'permalinks', param( 'permalinks', 'string', '' ) );
 680              $this->set_setting( '404_response', param( '404_response', 'string', '' ) );
 681              $this->set_setting( 'help_link', param( 'help_link', 'string', '' ) );
 682              $this->set_setting( 'excerpts_meta_description', param( 'excerpts_meta_description', 'integer', 0 ) );
 683              $this->set_setting( 'categories_meta_description', param( 'categories_meta_description', 'integer', 0 ) );
 684              $this->set_setting( 'tags_meta_keywords', param( 'tags_meta_keywords', 'integer', 0 ) );
 685          }
 686  
 687  
 688          /*
 689           * ADVANCED ADMIN SETTINGS
 690           */
 691          if( $current_User->check_perm( 'blog_admin', 'edit', false, $this->ID ) )
 692          {    // We have permission to edit advanced admin settings:
 693  
 694              if( in_array( 'cache', $groups ) )
 695              { // we want to load the cache params:
 696                  $this->set_setting( 'ajax_form_enabled', param( 'ajax_form_enabled', 'integer', 0 ) );
 697                  $this->set_setting( 'ajax_form_loggedin_enabled', param( 'ajax_form_loggedin_enabled', 'integer', 0 ) );
 698                  $this->set_setting( 'cache_enabled_widgets', param( 'cache_enabled_widgets', 'integer', 0 ) );
 699              }
 700  
 701              if( in_array( 'styles', $groups ) )
 702              { // we want to load the styles params:
 703                  $this->set( 'allowblogcss', param( 'blog_allowblogcss', 'integer', 0 ) );
 704                  $this->set( 'allowusercss', param( 'blog_allowusercss', 'integer', 0 ) );
 705              }
 706  
 707              if( in_array( 'login', $groups ) )
 708              { // we want to load the login params:
 709                  $this->set_setting( 'in_skin_login', param( 'in_skin_login', 'integer', 0 ) );
 710                  $this->set_setting( 'in_skin_editing', param( 'in_skin_editing', 'integer', 0 ) );
 711              }
 712  
 713              if( param( 'blog_head_includes', 'html', NULL ) !== NULL )
 714              {    // HTML header includes:
 715                  param_check_html( 'blog_head_includes', T_('Invalid Custom meta section') );
 716                  $this->set_setting( 'head_includes', get_param( 'blog_head_includes' ) );
 717              }
 718  
 719              if( param( 'blog_footer_includes', 'html', NULL ) !== NULL )
 720              {    // HTML header includes:
 721                  param_check_html( 'blog_footer_includes', T_('Invalid Custom javascript section') );
 722                  $this->set_setting( 'footer_includes', get_param( 'blog_footer_includes' ) );
 723              }
 724  
 725              if( param( 'owner_login', 'string', NULL ) !== NULL )
 726              { // Permissions:
 727                  $UserCache = & get_UserCache();
 728                  $owner_User = & $UserCache->get_by_login( get_param('owner_login') );
 729                  if( empty( $owner_User ) )
 730                  {
 731                      param_error( 'owner_login', sprintf( T_('User &laquo;%s&raquo; does not exist!'), get_param('owner_login') ) );
 732                  }
 733                  else
 734                  {
 735                      $this->set( 'owner_user_ID', $owner_User->ID );
 736                      $this->owner_User = & $owner_User;
 737                  }
 738              }
 739  
 740  
 741              if( ($blog_urlname = param( 'blog_urlname', 'string', NULL )) !== NULL )
 742              {    // check urlname
 743                  if( param_check_not_empty( 'blog_urlname', T_('You must provide an URL blog name!') ) )
 744                  {
 745                      if( ! preg_match( '|^[A-Za-z0-9\-]+$|', $blog_urlname ) )
 746                      {
 747                          param_error( 'blog_urlname', sprintf( T_('The url name %s is invalid.'), "&laquo;$blog_urlname&raquo;" ) );
 748                          $blog_urlname = NULL;
 749                      }
 750  
 751                      if( isset($blog_urlname) && $DB->get_var( 'SELECT COUNT(*)
 752                                                              FROM T_blogs
 753                                                              WHERE blog_urlname = '.$DB->quote($blog_urlname).'
 754                                                              AND blog_ID <> '.$this->ID
 755                                                          ) )
 756                      { // urlname is already in use
 757                          param_error( 'blog_urlname', sprintf( T_('The URL name %s is already in use by another blog. Please choose another name.'), "&laquo;$blog_urlname&raquo;" ) );
 758                          $blog_urlname = NULL;
 759                      }
 760  
 761                      if( isset($blog_urlname) )
 762                      {
 763                          $this->set_from_Request( 'urlname' );
 764                      }
 765                  }
 766              }
 767  
 768  
 769              if( ($access_type = param( 'blog_access_type', 'string', NULL )) !== NULL )
 770              { // Blog URL parameters:
 771                  // Note: We must avoid to set an invalid url, because the new blog url will be displayed in the evobar even if it was not saved
 772                  $allow_new_access_type = true;
 773  
 774                  if( $access_type == 'absolute' )
 775                  {
 776                      $blog_siteurl = param( 'blog_siteurl_absolute', 'string', true );
 777                      if( preg_match( '#^https?://[^/]+/.*#', $blog_siteurl, $matches ) )
 778                      { // It looks like valid absolute URL, so we may update the blog siteurl
 779                          $this->set( 'siteurl', $blog_siteurl );
 780                      }
 781                      else
 782                      { // It is not valid absolute URL, don't update the blog 'siteurl' to avoid errors
 783                          $allow_new_access_type = false; // If site url is not updated do not allow access_type update either
 784                          $Messages->add( T_('Blog Folder URL').': '.sprintf( T_('%s is an invalid absolute URL'), '&laquo;'.htmlspecialchars( $blog_siteurl ).'&raquo;' )
 785                              .' '.T_('You must provide an absolute URL (starting with <code>http://</code> or <code>https://</code>) and it must contain at least one \'/\' sign after the domain name!'), 'error' );
 786                      }
 787                  }
 788                  elseif( $access_type == 'relative' )
 789                  { // relative siteurl
 790                      $blog_siteurl = param( 'blog_siteurl_relative', 'string', true );
 791                      if( preg_match( '#^https?://#', $blog_siteurl ) )
 792                      {
 793                          $Messages->add( T_('Blog Folder URL').': '
 794                                                          .T_('You must provide a relative URL (without <code>http://</code> or <code>https://</code>)!'), 'error' );
 795                      }
 796                      $this->set( 'siteurl', $blog_siteurl );
 797                  }
 798                  else
 799                  {
 800                      $this->set( 'siteurl', '' );
 801                  }
 802  
 803                  if( $allow_new_access_type )
 804                  { // The received siteurl value was correct, may update the access_type value
 805                      $this->set( 'access_type', $access_type );
 806                  }
 807              }
 808  
 809  
 810              if( param( 'aggregate_coll_IDs', 'string', NULL ) !== NULL )
 811              { // Aggregate list: (can be '*')
 812                  $aggregate_coll_IDs = get_param( 'aggregate_coll_IDs' );
 813  
 814                  if( $aggregate_coll_IDs != '*' )
 815                  {    // Sanitize the string
 816                      $aggregate_coll_IDs = sanitize_id_list($aggregate_coll_IDs);
 817                  }
 818  
 819                  // fp> TODO: check perms on each aggregated blog (if changed)
 820                  // fp> TODO: better interface
 821                  if( $aggregate_coll_IDs != '*' && !preg_match( '#^([0-9]+(,[0-9]+)*)?$#', $aggregate_coll_IDs ) )
 822                  {
 823                      param_error( 'aggregate_coll_IDs', T_('Invalid aggregate blog ID list!') );
 824                  }
 825                  $this->set_setting( 'aggregate_coll_IDs', $aggregate_coll_IDs );
 826              }
 827  
 828  
 829              if( param( 'blog_media_location',  'string', NULL ) !== NULL )
 830              {    // Media files location:
 831                  $old_media_dir = $this->get_media_dir();
 832                  $this->set_from_Request( 'media_location' );
 833                  $this->set_media_subdir( param( 'blog_media_subdir', 'string', '' ) );
 834                  $this->set_media_fullpath( param( 'blog_media_fullpath', 'string', '' ) );
 835                  $this->set_media_url( param( 'blog_media_url', 'string', '' ) );
 836  
 837                  // check params
 838                  switch( $this->get( 'media_location' ) )
 839                  {
 840                      case 'custom': // custom path and URL
 841                          global $demo_mode, $media_path;
 842                          if( $this->get( 'media_fullpath' ) == '' )
 843                          {
 844                              param_error( 'blog_media_fullpath', T_('Media dir location').': '.T_('You must provide the full path of the media directory.') );
 845                          }
 846                          if( !preg_match( '#^https?://#', $this->get( 'media_url' ) ) )
 847                          {
 848                              param_error( 'blog_media_url', T_('Media dir location').': '
 849                                                              .T_('You must provide an absolute URL (starting with <code>http://</code> or <code>https://</code>)!') );
 850                          }
 851                          if( $demo_mode )
 852                          {
 853                              $canonical_fullpath = get_canonical_path($this->get('media_fullpath'));
 854                              if( ! $canonical_fullpath || strpos($canonical_fullpath, $media_path) !== 0 )
 855                              {
 856                                  param_error( 'blog_media_fullpath', T_('Media dir location').': in demo mode the path must be inside of $media_path.' );
 857                              }
 858                          }
 859                          break;
 860  
 861                      case 'subdir':
 862                          global $media_path;
 863                          if( $this->get( 'media_subdir' ) == '' )
 864                          {
 865                              param_error( 'blog_media_subdir', T_('Media dir location').': '.T_('You must provide the media subdirectory.') );
 866                          }
 867                          else
 868                          { // Test if it's below $media_path (subdir!)
 869                              $canonical_path = get_canonical_path($media_path.$this->get( 'media_subdir' ));
 870                              if( ! $canonical_path || strpos($canonical_path, $media_path) !== 0 )
 871                              {
 872                                  param_error( 'blog_media_subdir', T_('Media dir location').': '.sprintf(T_('Invalid subdirectory &laquo;%s&raquo;.'), format_to_output($this->get('media_subdir'))) );
 873                              }
 874                              else
 875                              {
 876                                  // Validate if it's a valid directory name:
 877                                  $subdir = no_trailing_slash(substr($canonical_path, strlen($media_path)));
 878                                  if( $error = validate_dirname($subdir) )
 879                                  {
 880                                      param_error( 'blog_media_subdir', T_('Media dir location').': '.$error );
 881                                  }
 882                              }
 883                          }
 884                          break;
 885                  }
 886  
 887                  if( ! param_errors_detected() )
 888                  { // If no error were created before we can try to move old files to new file root
 889                      $FileRootCache = & get_FileRootCache();
 890                      if( ( $blog_FileRoot = & $FileRootCache->get_by_type_and_ID( 'collection', $this->ID ) ) !== false )
 891                      {
 892                          $new_media_dir = $blog_FileRoot->ads_path;
 893                          if( ! empty( $old_media_dir ) && ! empty( $new_media_dir ) &&
 894                              $old_media_dir != $new_media_dir )
 895                          { // Blog's media dir was changed, We should move the files from old to new dir
 896                              if( ! @rename( $old_media_dir, $new_media_dir ) )
 897                              { // Some error on renaming
 898                                  $Messages->add( sprintf( T_('You cannot choose new media dir "%s" (cannot rename blog fileroot)'), $new_media_dir ), 'error' );
 899                              }
 900                          }
 901                      }
 902                  }
 903              }
 904          }
 905  
 906          return ! param_errors_detected();
 907      }
 908  
 909  
 910      /**
 911       * Load blog custom fields setting
 912       *
 913       * @param string custom field types
 914       * @param string query to remove deleted custom field settings from items
 915       * @param array Field names array is used to check the diplicates
 916       */
 917  	function load_custom_fields( $type, & $update_cascade_query, & $field_names )
 918      {
 919          global $DB, $Messages;
 920  
 921          $empty_title_error = false; // use this to display empty title fields error message only ones
 922          $real_custom_field_count = 0; // custom fields count after update
 923          $custom_field_count = param( 'count_custom_'.$type, 'integer', 0 ); // all custom fields count ( contains even deleted fields )
 924          $delted_field_guids = param( 'deleted_custom_'.$type, 'string', '' );
 925          if( ( $custom_field_count == 0 ) && empty( $delted_field_guids ) )
 926          { // There were no custom field add, update or delete request so no need for further checks
 927              return;
 928          }
 929          $deleted_custom_fields = explode( ',', $delted_field_guids );
 930  
 931          // Update custom fields
 932          for( $i = 1 ; $i <= $custom_field_count; $i++ )
 933          {
 934              $custom_field_guid = param( 'custom_'.$type.'_guid'.$i, '/^[a-z0-9\-_]+$/', NULL );
 935              if( in_array( $custom_field_guid, $deleted_custom_fields ) )
 936              { // This field was deleted, don't neeed to update
 937                  continue;
 938              }
 939  
 940              $real_custom_field_count++;
 941              $custom_field_value = param( 'custom_'.$type.'_'.$i, 'string', NULL );
 942              $custom_field_name = param( 'custom_'.$type.'_fname'.$i, '/^[a-z0-9\-_]+$/', NULL );
 943              if( empty( $custom_field_value ) )
 944              { // Field title can't be emtpy
 945                  if( !$empty_title_error )
 946                  { // This message was not displayed yet
 947                      $Messages->add( T_('Custom field titles can\'t be empty!') );
 948                      $empty_title_error = true;
 949                  }
 950              }
 951              elseif( empty( $custom_field_name ) )
 952              { // Field identical name can't be emtpy
 953                  $Messages->add( sprintf( T_('Please enter name for custom field "%s"'), $custom_field_value ) );
 954              }
 955              elseif( in_array( $custom_field_name, $field_names ) )
 956              { // Field name must be identical
 957                  $Messages->add( sprintf( T_('The field name "%s" is not identical, please use another.'), $custom_field_value ) );
 958              }
 959              else
 960              { // Add new identical field name
 961                  $field_names[] = $custom_field_name;
 962              }
 963              // Update field settings
 964              $this->set_setting( 'custom_'.$type.$real_custom_field_count, $custom_field_guid );
 965              $this->set_setting( 'custom_'.$type.'_'.$custom_field_guid, $custom_field_value );
 966              $this->set_setting( 'custom_fname_'.$custom_field_guid, $custom_field_name );
 967          }
 968  
 969          // get custom field count from db
 970          $db_custom_field_count = $this->get_setting( 'count_custom_'.$type );
 971          for( $i = $real_custom_field_count + 1 ; $i <= $db_custom_field_count; $i++ )
 972          { // delete not wanted settings by index
 973              $this->delete_setting( 'custom_'.$type.$i );
 974          }
 975          foreach( $deleted_custom_fields as $delted_field_guid )
 976          { // delete not wanted settings by guid
 977              if( empty( $update_cascade_query ) )
 978              {
 979                  $update_cascade_query = 'DELETE FROM T_items__item_settings WHERE iset_name = "custom_'.$type.'_'.$delted_field_guid.'"';
 980              }
 981              else
 982              {
 983                  $update_cascade_query .= ' OR iset_name = "custom_'.$type.'_'.$delted_field_guid.'"';
 984              }
 985              $this->delete_setting( 'custom_fname_'.$delted_field_guid );
 986              $this->delete_setting( 'custom_'.$type.'_'.$delted_field_guid );
 987          }
 988          // update number of custom fields
 989          $this->set_setting( 'count_custom_'.$type, $real_custom_field_count );
 990      }
 991  
 992  
 993      /**
 994       * Set the media folder's subdir
 995       *
 996       * @param string the subdirectory
 997       */
 998  	function set_media_subdir( $path )
 999      {
1000          parent::set_param( 'media_subdir', 'string', trailing_slash( $path ) );
1001      }
1002  
1003  
1004      /**
1005       * Set the full path of the media folder
1006       *
1007       * @param string the full path
1008       */
1009  	function set_media_fullpath( $path )
1010      {
1011          parent::set_param( 'media_fullpath', 'string', trailing_slash( $path ) );
1012      }
1013  
1014  
1015      /**
1016       * Set the full URL of the media folder
1017       *
1018       * @param string the full URL
1019       */
1020  	function set_media_url( $url )
1021      {
1022          parent::set_param( 'media_url', 'string', trailing_slash( $url ) );
1023      }
1024  
1025  
1026      /**
1027       * Set param value
1028       *
1029       * @param string Parameter name
1030       * @param boolean true to set to NULL if empty value
1031       * @return boolean true, if a value has been set; false if it has not changed
1032       */
1033  	function set( $parname, $parvalue, $make_null = false )
1034      {
1035          global $Settings;
1036  
1037          switch( $parname )
1038          {
1039              case 'ID':
1040              case 'allowtrackbacks':
1041              case 'blog_in_bloglist':
1042                  return $this->set_param( $parname, 'number', $parvalue, $make_null );
1043                  break;
1044  
1045              case 'shortdesc':
1046                  $this->shortdesc = $parvalue;
1047                  return $this->set_param( 'description', 'string', $parvalue, $make_null );
1048                  break;
1049  
1050              default:
1051                  return $this->set_param( $parname, 'string', $parvalue, $make_null );
1052          }
1053      }
1054  
1055  
1056      /**
1057       * Generate blog URL. That is the URL of the main page/home page of the blog.
1058       * This will nto necessarily be a folder. For example, it can end in index.php?blog=4
1059       *
1060       * @param string default|dynamic|static
1061       */
1062  	function gen_blogurl( $type = 'default' )
1063      {
1064          global $baseurl, $basedomain, $Settings;
1065  
1066          switch( $this->access_type )
1067          {
1068              case 'default':
1069                  // Access through index.php: match absolute URL or call default blog
1070                  if( ( $Settings->get('default_blog_ID') == $this->ID )
1071                      || preg_match( '#^https?://#', $this->siteurl ) )
1072                  { // Safety check! We only do that kind of linking if this is really the default blog...
1073                      // or if we call by absolute URL
1074                      return $baseurl.$this->siteurl.'index.php';
1075                  }
1076                  // ... otherwise, we add the blog ID:
1077  
1078              case 'index.php':
1079                  // Access through index.php + blog qualifier
1080                  return $baseurl.$this->siteurl.'index.php?blog='.$this->ID;
1081  
1082              case 'extrapath':
1083                  // We want to use extra path info, use the blog urlname:
1084                  return $baseurl.$this->siteurl.'index.php/'.$this->urlname.'/';
1085  
1086              case 'relative':
1087                  return $baseurl.$this->siteurl;
1088  
1089              case 'subdom':
1090                  return preg_replace( '#(https?://)#i', '$1'.$this->urlname.'.', $baseurl );
1091  
1092              case 'absolute':
1093                  return $this->siteurl;
1094  
1095              default:
1096                  debug_die( 'Unhandled Blog access type ['.$this->access_type.']' );
1097          }
1098      }
1099  
1100  
1101      /**
1102       * Generate the baseurl of the blog (URL of the folder where the blog lives).
1103       * Will always end with '/'.
1104       */
1105  	function gen_baseurl()
1106      {
1107          global $baseurl, $basedomain;
1108  
1109          switch( $this->access_type )
1110          {
1111              case 'default':
1112              case 'index.php':
1113                  return $baseurl.$this->siteurl.'index.php/';
1114  
1115              case 'extrapath':
1116                  // We want to use extra path info, use the blog urlname:
1117                  return $baseurl.$this->siteurl.'index.php/'.$this->urlname.'/';
1118  
1119              case 'relative':
1120                  $url = $baseurl.$this->siteurl;
1121                  break;
1122  
1123              case 'subdom':
1124                  return preg_replace( '#(https?://)#i', '$1'.$this->urlname.'.', $baseurl );
1125  
1126              case 'absolute':
1127                  $url = $this->siteurl;
1128                  break;
1129  
1130              default:
1131                  debug_die( 'Unhandled Blog access type ['.$this->access_type.']' );
1132          }
1133  
1134          if( substr( $url, -1 ) != '/' )
1135          { // Crop an url part after the last "/"
1136              $url = substr( $url, 0, strrpos( $url, '/' ) + 1 );
1137          }
1138  
1139          // For case relative and absolute:
1140          return preg_replace( '~^(.+)/[^/]$~', '$1/', $url );
1141      }
1142  
1143  
1144      /**
1145       * This is the domain of the blog.
1146       * This returns NO trailing slash.
1147       */
1148  	function get_baseurl_root()
1149      {
1150          if( preg_match( '#^(https?://(.+?)(:.+?)?)/#', $this->gen_baseurl(), $matches ) )
1151          {
1152              return $matches[1];
1153          }
1154          debug_die( 'Blog::get(baseurl)/baseurlroot - assertion failed [baseurl: '.$this->gen_baseurl().'].' );
1155      }
1156  
1157  
1158      /**
1159       * Get the URL to the basepath of that blog.
1160       * This is supposed to be the same as $baseurl but localized to the domain of the blog/
1161       *
1162       * @todo The current implementation may not work in all situations. See TODO below.
1163       */
1164  	function get_basepath_url()
1165      {
1166          global $basesubpath;
1167  
1168          // fp> TODO: this may be very borked and may need some tweaking for non standard multiblog situations:
1169          // One way to fix this, if neede, may be to add a settinf to Blog Settings > URLs
1170          // -- Create a block for "System URLs" and give a radio option between default and custom with input field
1171  
1172          if( empty($this->basepath_url) )
1173          {
1174              $this->basepath_url = $this->get_baseurl_root().$basesubpath;
1175          }
1176  
1177          return $this->basepath_url;
1178      }
1179  
1180  
1181      /**
1182       * Get the URL of the htsrv folder, on the current blog's domain (which is NOT always the same as the $baseurl domain!).
1183       */
1184  	function get_local_htsrv_url()
1185      {
1186          global $htsrv_subdir;
1187  
1188          return $this->get_basepath_url().$htsrv_subdir;
1189      }
1190  
1191  
1192      /**
1193       * Get the URL of the media folder, on the current blog's domain (which is NOT always the same as the $baseurl domain!).
1194       */
1195  	function get_local_media_url()
1196      {
1197          global $media_subdir;
1198  
1199          return $this->get_basepath_url().$media_subdir;
1200      }
1201  
1202  
1203      /**
1204       * Get the URL of the rsc folder, on the current blog's domain (which is NOT always the same as the $baseurl domain!).
1205       */
1206  	function get_local_rsc_url()
1207      {
1208          global $rsc_subdir;
1209  
1210          return $this->get_basepath_url().$rsc_subdir;
1211      }
1212  
1213  
1214      /**
1215       * Get the URL of the skins folder, on the current blog's domain (which is NOT always the same as the $baseurl domain!).
1216       */
1217  	function get_local_skins_url()
1218      {
1219          global $skins_subdir;
1220  
1221          return $this->get_basepath_url().$skins_subdir;
1222      }
1223  
1224  
1225      /**
1226       * Get the URL of the xmlsrv folder, on the current blog's domain (which is NOT always the same as the $baseurl domain!).
1227       */
1228  	function get_local_xmlsrv_url()
1229      {
1230          global $xmlsrv_subdir;
1231  
1232          return $this->get_basepath_url().$xmlsrv_subdir;
1233      }
1234  
1235  
1236      /**
1237       * Generate archive page URL
1238       *
1239       * Note: there ate two similar functions here.
1240       * @see Blog::get_archive_url()
1241       *
1242       * @param string year
1243       * @param string month
1244       * @param string day
1245       * @param string week
1246       */
1247  	function gen_archive_url( $year, $month = NULL, $day = NULL, $week = NULL, $glue = '&amp;', $paged = 1 )
1248      {
1249          $blogurl = $this->gen_blogurl();
1250  
1251          $archive_links = $this->get_setting('archive_links');
1252  
1253          if( $archive_links == 'param' )
1254          {    // We reference by Query
1255              $separator = '';
1256          }
1257          else
1258          {    // We reference by extra path info
1259              $separator = '/';
1260          }
1261  
1262          $datestring = $separator.$year.$separator;
1263  
1264          if( !empty( $month ) )
1265          {
1266              $datestring .= zeroise($month,2).$separator;
1267              if( !empty( $day ) )
1268              {
1269                  $datestring .= zeroise($day,2).$separator;
1270              }
1271          }
1272          elseif( !is_null($week) && $week !== '' )  // Note: week # can be 0 !
1273          {
1274              if( $archive_links == 'param' )
1275              {    // We reference by Query
1276                  $datestring .= $glue.'w='.$week;
1277              }
1278              else
1279              {    // extra path info
1280                  $datestring .= 'w'.zeroise($week,2).'/';
1281              }
1282          }
1283  
1284          if( $archive_links == 'param' )
1285          {    // We reference by Query
1286              $link = url_add_param( $blogurl, 'm='.$datestring, $glue );
1287  
1288              $archive_posts_per_page = $this->get_setting( 'archive_posts_per_page' );
1289              if( !empty($archive_posts_per_page) && $archive_posts_per_page != $this->get_setting( 'posts_per_page' ) )
1290              {    // We want a specific post per page count:
1291                  $link = url_add_param( $link, 'posts='.$archive_posts_per_page, $glue );
1292              }
1293          }
1294          else
1295          {    // We reference by extra path info
1296              $link = url_add_tail( $blogurl, $datestring ); // there may already be a slash from a siteurl like 'http://example.com/'
1297          }
1298  
1299          if( $paged > 1 )
1300          {    // We want a specific page:
1301              $link = url_add_param( $link, 'paged='.$paged, $glue );
1302          }
1303  
1304          return $link;
1305      }
1306  
1307  
1308      /**
1309       * Generate link to archive
1310       * @uses Blog::gen_archive_url()
1311       * @return string HTML A tag
1312       */
1313  	function gen_archive_link( $text, $title, $year, $month = NULL, $day = NULL, $week = NULL, $glue = '&amp;', $paged = 1 )
1314      {
1315          $link = '<a';
1316  
1317          if( $this->get_setting( 'archive_nofollowto' ) )
1318          {
1319              $link .= ' rel="nofollow"';
1320          }
1321  
1322           if( !empty($title) )
1323          {
1324              $link .= ' title="'.format_to_output( $title, 'htmlattr' ).'"';
1325          }
1326  
1327          $link .= ' href="'.$this->gen_archive_url( $year, $month, $day, $week, $glue, $paged ).'" >';
1328          $link .= format_to_output( $text );
1329          $link .= '</a>';
1330  
1331          return $link;
1332      }
1333  
1334  
1335      /**
1336       * Get archive page URL
1337       *
1338       * Note: there are two similar functions here.
1339       *
1340       * @uses Blog::gen_archive_url()
1341       *
1342       * @param string monthly, weekly, daily
1343       */
1344  	function get_archive_url( $date, $glue = '&amp;' )
1345      {
1346          switch( $this->get_setting('archive_mode') )
1347          {
1348              case 'weekly':
1349                  global $cacheweekly, $DB;
1350                  if((!isset($cacheweekly)) || (empty($cacheweekly[$date])))
1351                  {
1352                      $cacheweekly[$date] = $DB->get_var( 'SELECT '.$DB->week( $DB->quote($date), locale_startofweek() ) );
1353                  }
1354                  return $this->gen_archive_url( substr( $date, 0, 4 ), NULL, NULL, $cacheweekly[$date], $glue );
1355                  break;
1356  
1357              case 'daily':
1358                  return $this->gen_archive_url( substr( $date, 0, 4 ), substr( $date, 5, 2 ), substr( $date, 8, 2 ), NULL, $glue );
1359                  break;
1360  
1361              case 'monthly':
1362              default:
1363                  return $this->gen_archive_url( substr( $date, 0, 4 ), substr( $date, 5, 2 ), NULL, NULL, $glue );
1364          }
1365      }
1366  
1367  
1368      /**
1369       * Generate a tag url on this blog
1370       */
1371  	function gen_tag_url( $tag, $paged = 1, $glue = '&' )
1372      {
1373          $link_type = $this->get_setting( 'tag_links' );
1374          switch( $link_type )
1375          {
1376              case 'param':
1377                  $r = url_add_param( $this->gen_blogurl(), 'tag='.urlencode( $tag ), $glue );
1378  
1379                  $tag_posts_per_page = $this->get_setting( 'tag_posts_per_page' );
1380                  if( !empty($tag_posts_per_page) && $tag_posts_per_page != $this->get_setting( 'posts_per_page' ) )
1381                  {    // We want a specific post per page count:
1382                      $r = url_add_param( $r, 'posts='.$tag_posts_per_page, $glue );
1383                  }
1384                  break;
1385  
1386              default:
1387                  switch( $link_type )
1388                  {
1389                      case 'dash':
1390                          $trailer = '-';
1391                          break;
1392                      case 'semicol': // dh> TODO: old value. I had this in my DB. Convert this during upgrade?
1393                      case 'semicolon':
1394                          $trailer = ';';
1395                          break;
1396                      case 'colon':
1397                          $trailer = ':';
1398                          break;
1399                      case 'prefix-only':
1400                      default:
1401                          $trailer = '';
1402                  }
1403                  $tag_prefix = $this->get_setting('tag_prefix');
1404                  if( !empty( $tag_prefix ) )
1405                  {
1406                      $r = url_add_tail( $this->gen_blogurl(), '/'.$tag_prefix.'/'.urlencode( $tag ).$trailer );
1407                  }
1408                  else
1409                  {
1410                      $r = url_add_tail( $this->gen_blogurl(), '/'.urlencode( $tag ).$trailer );
1411                  }
1412          }
1413  
1414          if( $paged > 1 )
1415          {    // We want a specific page:
1416              $r = url_add_param( $r, 'paged='.$paged, $glue );
1417          }
1418  
1419          return $r;
1420      }
1421  
1422  
1423      /**
1424       * Get a link (<a href>) to the tag page of a given tag.
1425       *
1426       * @param string Tag
1427       * @param string Link text (defaults to tag name)
1428       * @param array Additional attributes for the A tag (href gets overridden).
1429       * @return string The <a href> link
1430       */
1431  	function get_tag_link( $tag, $text = NULL, $attribs = array() )
1432      {
1433          if( $this->get_setting('tag_rel_attrib') && $this->get_setting('tag_links') == 'prefix-only' )
1434          {    // add rel=tag attrib -- valid only if the last part of the url is the tag name
1435              if( ! isset($attribs['rel']) )
1436                  $attribs['rel'] = 'tag';
1437              else
1438                  $attribs['rel'] .= ' tag';
1439          }
1440          $attribs['href'] = $this->gen_tag_url( $tag );
1441  
1442          if( is_null($text) )
1443          {
1444              $text = $tag;
1445          }
1446  
1447          return '<a'.get_field_attribs_as_string($attribs).'>'.$text.'</a>';
1448      }
1449  
1450  
1451      /**
1452       * Get allowed post status for current user in this blog
1453       *
1454       * @todo make default a Blog param
1455       *
1456       * @param string status to start with. Empty to use default.
1457       * @return string authorized status; NULL if none
1458       */
1459  	function get_allowed_item_status( $status = NULL )
1460      {
1461          /**
1462           * @var User
1463           */
1464          global $current_User;
1465  
1466          if( empty( $status ) )
1467          {
1468              $status = $this->get_setting('default_post_status');
1469          }
1470          if( ! $current_User->check_perm( 'blog_post!'.$status, 'create', false, $this->ID ) )
1471          { // We need to find another one:
1472              $status = NULL;
1473  
1474              if( $current_User->check_perm( 'blog_post!published', 'create', false, $this->ID ) )
1475                  $status = 'published';
1476              elseif( $current_User->check_perm( 'blog_post!community', 'create', false, $this->ID ) )
1477                  $status = 'community';
1478              elseif( $current_User->check_perm( 'blog_post!protected', 'create', false, $this->ID ) )
1479                  $status = 'protected';
1480              elseif( $current_User->check_perm( 'blog_post!private', 'create', false, $this->ID ) )
1481                  $status = 'private';
1482              elseif( $current_User->check_perm( 'blog_post!review', 'create', false, $this->ID ) )
1483                  $status = 'review';
1484              elseif( $current_User->check_perm( 'blog_post!draft', 'create', false, $this->ID ) )
1485                  $status = 'draft';
1486              elseif( $current_User->check_perm( 'blog_post!deprecated', 'create', false, $this->ID ) )
1487                  $status = 'deprecated';
1488              elseif( $current_User->check_perm( 'blog_post!redirected', 'create', false, $this->ID ) )
1489                  $status = 'redirected';
1490          }
1491          return $status;
1492      }
1493  
1494  
1495      /**
1496       * Get default category for current blog
1497       *
1498       * @todo fp> this is a super lame stub, but it's still better than nothing. Should be user configurable.
1499       *
1500       */
1501  	function get_default_cat_ID()
1502      {
1503          global $DB, $Settings;
1504  
1505          if( empty( $this->default_cat_ID ) )
1506          {
1507              if( $default_cat_ID = $this->get_setting('default_cat_ID') )
1508              {    // A specific cat has previosuly been configured as the default:
1509                  // Try to get it from the DB (to make sure it exists and is in teh right blog):
1510                  $sql = 'SELECT cat_ID
1511                            FROM T_categories
1512                           WHERE cat_blog_ID = '.$this->ID.'
1513                                AND cat_ID = '.$default_cat_ID;
1514                  $this->default_cat_ID = $DB->get_var( $sql, 0, 0, 'Get default category' );
1515              }
1516          }
1517  
1518          if( empty( $this->default_cat_ID ) )
1519          {    // If the previous query has returned NULL
1520              if( $Settings->get('chapter_ordering') == 'manual' )
1521              {    // Manual order
1522                  $select_temp_order = ', IF( cat_order IS NULL, 999999999, cat_order ) AS temp_order';
1523                  $sql_order = ' ORDER BY temp_order';
1524              }
1525              else
1526              {    // Alphabetic order
1527                  $select_temp_order = '';
1528                  $sql_order = ' ORDER BY cat_name';
1529              }
1530              $sql = 'SELECT cat_ID'.$select_temp_order.'
1531                        FROM T_categories
1532                       WHERE cat_blog_ID = '.$this->ID
1533                       .$sql_order
1534                       .' LIMIT 1';
1535  
1536              $this->default_cat_ID = $DB->get_var( $sql, 0, 0, 'Get default category' );
1537          }
1538  
1539          return $this->default_cat_ID;
1540      }
1541  
1542  
1543      /**
1544       * Get the blog's media directory (and create it if necessary).
1545       *
1546       * If we're {@link is_admin_page() on an admin page}, it adds status messages.
1547       * @todo These status messages should rather go to a "syslog" and not be displayed to a normal user
1548       * @todo dh> refactor this into e.g. create_media_dir() and use it for Blog::get_media_dir, too.
1549       *
1550       * @param boolean Create the directory, if it does not exist yet?
1551       * @return string path string on success, false if the dir could not be created
1552       */
1553  	function get_media_dir( $create = true )
1554      {
1555          global $media_path, $current_User, $Messages, $Settings, $Debuglog;
1556  
1557          if( ! $Settings->get( 'fm_enable_roots_blog' ) )
1558          { // User directories are disabled:
1559              $Debuglog->add( 'Attempt to access blog media dir, but this feature is globally disabled', 'files' );
1560              return false;
1561          }
1562  
1563          switch( $this->media_location )
1564          {
1565              case 'default':
1566                  $mediadir = get_canonical_path( $media_path.'blogs/'.$this->urlname.'/' );
1567                  break;
1568  
1569              case 'subdir':
1570                  $mediadir = get_canonical_path( $media_path.$this->media_subdir );
1571                  break;
1572  
1573              case 'custom':
1574                  $mediadir = get_canonical_path( $this->media_fullpath );
1575                  break;
1576  
1577              case 'none':
1578              default:
1579                  $Debuglog->add( 'Attempt to access blog media dir, but this feature is disabled for this blog', 'files' );
1580                  return false;
1581          }
1582  
1583          // TODO: use a File object here (to access perms, ..), using FileCache::get_by_root_and_path().
1584          if( $create && ! is_dir( $mediadir ) )
1585          {
1586              // Display absolute path to blog admin and relative path to everyone else
1587              $msg_mediadir_path = ( is_logged_in() && $current_User->check_perm( 'blog_admin', 'edit', false, $this->ID ) ) ? $mediadir : rel_path_to_base( $mediadir );
1588  
1589              // TODO: Link to some help page(s) with errors!
1590              if( ! is_writable( dirname($mediadir) ) )
1591              { // add error
1592                  if( is_admin_page() )
1593                  {
1594                      $Messages->add( sprintf( T_("The blog's media directory &laquo;%s&raquo; could not be created, because the parent directory is not writable or does not exist."), $msg_mediadir_path )
1595                                  .get_manual_link('media_file_permission_errors'), 'error' );
1596                  }
1597                  return false;
1598              }
1599              elseif( ! evo_mkdir( $mediadir ) )
1600              { // add error
1601                  if( is_admin_page() )
1602                  {
1603                      $Messages->add( sprintf( T_("The blog's media directory &laquo;%s&raquo; could not be created."), $msg_mediadir_path )
1604                                  .get_manual_link('directory_creation_error'), 'error' );
1605                  }
1606                  return false;
1607              }
1608              else
1609              { // add note:
1610                  if( is_admin_page() )
1611                  {
1612                      $Messages->add( sprintf( T_("The blog's media directory &laquo;%s&raquo; has been created with permissions %s."), $msg_mediadir_path, substr( sprintf('%o', fileperms($mediadir)), -3 ) ), 'success' );
1613                  }
1614              }
1615          }
1616  
1617          return $mediadir;
1618      }
1619  
1620  
1621      /**
1622       * Get the URL to the media folder
1623       *
1624       * @return string the URL
1625       */
1626  	function get_media_url()
1627      {
1628          global $media_subdir, $Settings, $Debuglog;
1629  
1630          if( ! $Settings->get( 'fm_enable_roots_blog' ) )
1631          { // User directories are disabled:
1632              $Debuglog->add( 'Attempt to access blog media URL, but this feature is disabled', 'files' );
1633              return false;
1634          }
1635  
1636          switch( $this->media_location )
1637          {
1638              case 'default':
1639                  return $this->get_local_media_url().'blogs/'.$this->urlname.'/';
1640  
1641              case 'subdir':
1642                  return $this->get_local_media_url().$this->media_subdir;
1643                  break;
1644  
1645              case 'custom':
1646                  return $this->media_url;
1647  
1648              case 'none':
1649              default:
1650                  $Debuglog->add( 'Attempt to access blog media url, but this feature is disabled for this blog', 'files' );
1651                  return false;
1652          }
1653      }
1654  
1655  
1656      /**
1657        * Get link to edit files
1658        *
1659        * @param string link (false on error)
1660       */
1661  	function get_filemanager_link()
1662      {
1663          global $admin_url;
1664  
1665          load_class( '/files/model/_fileroot.class.php', 'FileRoot' );
1666          return $admin_url.'?ctrl=files&amp;root='.FileRoot::gen_ID( 'collection', $this->ID );
1667      }
1668  
1669  
1670      /**
1671       * Get URL to display the blog with a temporary skin.
1672       *
1673       * This is used to construct the various RSS/Atom feeds
1674       *
1675       * @param string
1676       * @param string
1677       * @param boolean
1678       */
1679  	function get_tempskin_url( $skin_folder_name, $additional_params = '', $halt_on_error = false )
1680      {
1681          /**
1682           * @var SkinCache
1683           */
1684           $SkinCache = & get_SkinCache();
1685          if( ! $Skin = & $SkinCache->get_by_folder( $skin_folder_name, $halt_on_error ) )
1686          {
1687              return NULL;
1688          }
1689  
1690          return url_add_param( $this->gen_blogurl( 'default' ), 'tempskin='.$skin_folder_name );
1691      }
1692  
1693  
1694      /**
1695       * Get URL to display the blog posts in an XML feed.
1696       *
1697       * @param string
1698       */
1699  	function get_item_feed_url( $skin_folder_name )
1700      {
1701          return $this->get_tempskin_url( $skin_folder_name );
1702      }
1703  
1704  
1705      /**
1706       * Get URL to display the blog comments in an XML feed.
1707       *
1708       * @param string
1709       */
1710  	function get_comment_feed_url( $skin_folder_name )
1711      {
1712          return url_add_param( $this->get_tempskin_url( $skin_folder_name ), 'disp=comments' );
1713      }
1714  
1715  
1716      /**
1717       * Callback function for footer_text()
1718       * @param array
1719       * @return string
1720       */
1721  	function replace_callback( $matches )
1722      {
1723          global $localtimenow;
1724  
1725          switch( $matches[1] )
1726          {
1727              case 'year':
1728                  // for copyrigth year
1729                  return date( 'Y', $localtimenow );
1730  
1731              case 'owner':
1732                  /**
1733                   * @var User
1734                   */
1735                  $owner_User = $this->get_owner_User();
1736                  // Full name gets priority over prefered name because it makes more sense for DEFAULT copyright.
1737                  // Blog owner can set WHATEVER footer text she wants through the admin interface.
1738                  $owner = $owner_User->get( 'fullname' );
1739                  if( empty($owner) )
1740                  {
1741                      $owner = $owner_User->get_preferred_name();
1742                  }
1743                  return $owner;
1744  
1745              default:
1746                  return $matches[1];
1747          }
1748      }
1749  
1750  
1751      /**
1752       * Get a param.
1753       *
1754       * @param string Parameter name
1755       * @return false|string The value as string or false in case of error (e.g. media dir is disabled).
1756       */
1757  	function get( $parname )
1758      {
1759          global $xmlsrv_url, $baseurl, $basepath, $media_url, $current_User, $Settings, $Debuglog;
1760  
1761          switch( $parname )
1762          {
1763              case 'blogurl':        // Deprecated
1764              case 'link':          // Deprecated
1765              case 'url':
1766                  return $this->gen_blogurl( 'default' );
1767  
1768              case 'baseurl':
1769                  return $this->gen_baseurl();
1770  
1771              case 'baseurlroot':
1772                  return $this->get_baseurl_root();
1773  
1774              case 'lastcommentsurl':
1775                  return url_add_param( $this->gen_blogurl(), 'disp=comments' );
1776  
1777              case 'searchurl':
1778                  return url_add_param( $this->gen_blogurl(), 'disp=search' );
1779  
1780              case 'arcdirurl':
1781                  return url_add_param( $this->gen_blogurl(), 'disp=arcdir' );
1782  
1783              case 'catdirurl':
1784                  return url_add_param( $this->gen_blogurl(), 'disp=catdir' );
1785  
1786              case 'postidxurl':
1787                  return url_add_param( $this->gen_blogurl(), 'disp=postidx' );
1788  
1789              case 'mediaidxurl':
1790                  return url_add_param( $this->gen_blogurl(), 'disp=mediaidx' );
1791  
1792              case 'sitemapurl':
1793                  return url_add_param( $this->gen_blogurl(), 'disp=sitemap' );
1794  
1795              case 'msgformurl':
1796                  return url_add_param( $this->gen_blogurl(), 'disp=msgform' );
1797  
1798              case 'userurl':
1799                  return url_add_param( $this->gen_blogurl(), 'disp=user' );
1800  
1801              case 'usersurl':
1802                  return url_add_param( $this->gen_blogurl(), 'disp=users' );
1803  
1804              case 'loginurl':
1805                  return url_add_param( $this->gen_blogurl(), 'disp=login' );
1806  
1807              case 'subsurl':
1808                  return url_add_param( $this->gen_blogurl(), 'disp=subs#subs' );
1809  
1810              case 'helpurl':
1811                  if( $this->get_setting( 'help_link' ) == 'slug' )
1812                  {
1813                      return url_add_tail( $this->gen_blogurl(), '/help' );
1814                  }
1815                  else
1816                  {
1817                      return url_add_param( $this->gen_blogurl(), 'disp=help' );
1818                  }
1819  
1820              case 'skin_ID':
1821                  return $this->get_skin_ID();
1822  
1823              case 'description':            // RSS wording
1824              case 'shortdesc':
1825                  return $this->shortdesc;
1826  
1827              case 'rdf_url':
1828                  return $this->get_item_feed_url( '_rdf' );
1829  
1830              case 'rss_url':
1831                  return $this->get_item_feed_url( '_rss' );
1832  
1833              case 'rss2_url':
1834                  return $this->get_item_feed_url( '_rss2' );
1835  
1836              case 'atom_url':
1837                  return $this->get_item_feed_url( '_atom' );
1838  
1839              case 'comments_rdf_url':
1840                  return $this->get_comment_feed_url( '_rdf' );
1841  
1842              case 'comments_rss_url':
1843                  return $this->get_comment_feed_url( '_rss' );
1844  
1845              case 'comments_rss2_url':
1846                  return $this->get_comment_feed_url( '_rss2' );
1847  
1848              case 'comments_atom_url':
1849                  return $this->get_comment_feed_url( '_atom' );
1850  
1851              case 'rsd_url':
1852                  return $this->get_local_xmlsrv_url().'rsd.php?blog='.$this->ID;
1853  
1854              /* Add the html for a blog-specified stylesheet
1855               * All stylesheets will be included if the blog settings allow it
1856               * and the file "style.css" exists. CSS rules say that the latter style sheets can
1857               * override earlier stylesheets.
1858               */
1859              case 'blog_css':
1860                  if( $this->allowblogcss
1861                      && file_exists( $this->get_media_dir(false).'style.css' ) )
1862                  {
1863                      return '<link rel="stylesheet" href="'.$this->get_media_url().'style.css" type="text/css" />';
1864                  }
1865                  else
1866                  {
1867                      return '';
1868                  }
1869  
1870              /* Add the html for a user-specified stylesheet
1871               * All stylesheets will be included if the blog settings allow it
1872               * and the file "style.css" exists. CSS rules say that the latter style sheets can
1873               * override earlier stylesheets. A user-specified stylesheet will
1874               * override a blog-specified stylesheet which will override a skin stylesheet.
1875               */
1876              case 'user_css':
1877                  if( $this->allowusercss
1878                      && isset( $current_User )
1879                      && file_exists( $current_User->get_media_dir(false).'style.css' ) )
1880                  {
1881                      return '<link rel="stylesheet" href="'.$current_User->get_media_url().'style.css" type="text/css" />';
1882                  }
1883                  else
1884                  {
1885                      return '';
1886                  }
1887  
1888  
1889              default:
1890                  // All other params:
1891                  return parent::get( $parname );
1892          }
1893      }
1894  
1895  
1896      /**
1897       * Get warning message about the enabled advanced perms for those cases when we grant some permission for anonymous users which can be restricted for logged in users
1898       *
1899       * @return mixed NULL if advanced perms are not enabled in this blog, the warning message otherwise
1900       */
1901  	function get_advanced_perms_warning()
1902      {
1903          global $admin_url;
1904  
1905          if( $this->get( 'advanced_perms' ) )
1906          {
1907              $warning = T_('ATTENTION: advanced <a href="%s">user</a> & <a href="%s">group</a> permissions are enabled and some logged in users may have less permissions than anonymous users.');
1908              $advanced_perm_url = url_add_param( $admin_url, 'ctrl=coll_settings&amp;blog='.$this->ID.'&amp;tab=' );
1909              return ' <span class="warning">'.sprintf( $warning, $advanced_perm_url.'perm', $advanced_perm_url.'permgroup' ).'</span>';
1910          }
1911  
1912          return NULL;
1913      }
1914  
1915  
1916       /**
1917       * Get a setting.
1918       *
1919       * @param string setting name
1920       * @param boolean true to return param's real value
1921       * @return string|false|NULL value as string on success; NULL if not found; false in case of error
1922       */
1923  	function get_setting( $parname, $real_value = false )
1924      {
1925          global $Settings;
1926  
1927          $this->load_CollectionSettings();
1928  
1929          $result = $this->CollectionSettings->get( $this->ID, $parname );
1930  
1931          switch( $parname )
1932          {
1933              case 'normal_skin_ID':
1934                  if( $result == NULL )
1935                  { // Try to get default from the global settings
1936                      $result = $Settings->get( 'def_'.$parname );
1937                  }
1938                  break;
1939  
1940              case 'mobile_skin_ID':
1941              case 'tablet_skin_ID':
1942                  if( $result == NULL )
1943                  { // Try to get default from the global settings
1944                      $result = $Settings->get( 'def_'.$parname );
1945                  }
1946                  if( ( $result === '0' ) && ! $real_value )
1947                  { // 0 value means that use the same as normal case
1948                      $result = $this->get_setting( 'normal_skin_ID' );
1949                  }
1950                  break;
1951  
1952              case 'moderation_statuses':
1953                  if( $result == NULL )
1954                  { // moderation_statuses was not set yet, set the default value, which depends from the blog type
1955                      $default = 'review,draft';
1956                      $result = ( $this->type == 'forum' ) ? 'community,protected,'.$default : $default;
1957                  }
1958                  break;
1959  
1960              case 'default_post_status':
1961              case 'new_feedback_status':
1962                  if( $result == NULL )
1963                  { // Default post/comment status was not set yet, use a default value corresponding to the blog type
1964                      $result = ( $this->type == 'forum' ) ? 'review' : 'draft';
1965                  }
1966                  break;
1967          }
1968  
1969          return $result;
1970      }
1971  
1972  
1973       /**
1974       * Get a ready-to-display setting from the DB settings table.
1975       *
1976       * Same as disp but don't echo
1977       *
1978       * @param string Name of setting
1979       * @param string Output format, see {@link format_to_output()}
1980       */
1981  	function dget_setting( $parname, $format = 'htmlbody' )
1982      {
1983          $this->load_CollectionSettings();
1984  
1985          return format_to_output( $this->CollectionSettings->get( $this->ID, $parname ), $format );
1986      }
1987  
1988  
1989       /**
1990       * Display a setting from the DB settings table.
1991       *
1992       * @param string Name of setting
1993       * @param string Output format, see {@link format_to_output()}
1994       */
1995  	function disp_setting( $parname, $format = 'htmlbody' )
1996      {
1997          $this->load_CollectionSettings();
1998  
1999          echo format_to_output( $this->CollectionSettings->get( $this->ID, $parname ), $format );
2000      }
2001  
2002  
2003       /**
2004       * Set a setting.
2005       *
2006       * @return boolean true, if the value has been set, false if it has not changed.
2007       */
2008  	function set_setting( $parname, $value, $make_null = false )
2009      {
2010           // Make sure collection settings are loaded
2011          $this->load_CollectionSettings();
2012  
2013          if( $make_null && empty($value) )
2014          {
2015              $value = NULL;
2016          }
2017  
2018          return $this->CollectionSettings->set( $this->ID, $parname, $value );
2019      }
2020  
2021  
2022      /**
2023       * Delete a setting.
2024       *
2025       * @return boolean true, if the value has been set, false if it has not changed.
2026       */
2027  	function delete_setting( $parname )
2028      {
2029           // Make sure collection settings are loaded
2030          $this->load_CollectionSettings();
2031  
2032          return $this->CollectionSettings->delete( $this->ID, $parname );
2033      }
2034  
2035  
2036      /**
2037       * Make sure collection settings are loaded.
2038       * This keeps a single instance across all blogs.
2039       * fp> why?
2040       */
2041  	function load_CollectionSettings()
2042      {
2043          static $instance; // fp> why do we need static? (it actually feels totally wrong: sharing settings between blogs!)
2044  
2045          if( ! isset($this->CollectionSettings) )
2046          {
2047              if( ! isset( $instance ) )
2048              {
2049                  load_class( 'collections/model/_collsettings.class.php', 'CollectionSettings' );
2050                  $instance = new CollectionSettings(); // COPY (function)
2051              }
2052              $this->CollectionSettings = $instance;
2053          }
2054      }
2055  
2056  
2057       /**
2058       * Insert into the DB
2059       */
2060  	function dbinsert()
2061      {
2062          global $DB, $Plugins;
2063  
2064          $DB->begin();
2065  
2066          if( parent::dbinsert() )
2067          {
2068              if( isset( $this->CollectionSettings ) )
2069              {
2070                  // So far all settings have been saved to collection #0 !
2071                  // Update the settings: hackish but the base class should not even store this value actually...
2072                  // dh> what do you mean? What "base class"? Is there a problem with CollectionSettings?
2073                  $this->CollectionSettings->cache[$this->ID] = $this->CollectionSettings->cache[0];
2074                  unset( $this->CollectionSettings->cache[0] );
2075  
2076                  $this->CollectionSettings->dbupdate();
2077              }
2078  
2079              $Plugins->trigger_event( 'AfterCollectionInsert', $params = array( 'Blog' => & $this ) );
2080          }
2081  
2082          $DB->commit();
2083      }
2084  
2085  
2086      /**
2087       * Create a new blog...
2088       *
2089       * @param string Kind of blog ( 'std', 'photo', 'group', 'forum' )
2090       */
2091  	function create( $kind = '' )
2092      {
2093          global $DB, $Messages, $basepath, $admin_url, $current_User, $Settings;
2094          $DB->begin();
2095  
2096          // DB INSERT
2097          $this->dbinsert();
2098  
2099          $Messages->add( T_('The new blog has been created.'), 'success' );
2100  
2101          // Change access mode if a stub file exists:
2102          $stub_filename = 'blog'.$this->ID.'.php';
2103          if( is_file( $basepath.$stub_filename ) )
2104          {    // Stub file exists and is waiting ;)
2105              $DB->query( 'UPDATE T_blogs
2106                          SET blog_access_type = "relative", blog_siteurl = "'.$stub_filename.'"
2107                          WHERE blog_ID = '.$this->ID );
2108              $Messages->add( sprintf(T_('The new blog has been associated with the stub file &laquo;%s&raquo;.'), $stub_filename ), 'success' );
2109          }
2110          elseif( $this->access_type == 'relative' )
2111          { // Show error message only if stub file should exists!
2112              $Messages->add( sprintf(T_('No stub file named &laquo;%s&raquo; was found. You must create it for the blog to function properly with the current settings.'), $stub_filename ), 'error' );
2113          }
2114  
2115          // Set default user permissions for this blog (All permissions for the current user, typically the admin who is creating the blog)
2116          // Note: current_User can be NULL only during new user registration process, when new user automatically get a new blog
2117          // Note: The owner of teh blog has permissions just by the sole fact he is registered as the owner.
2118          if( $current_User != NULL )
2119          { // Proceed insertions:
2120              $perm_statuses = "'review,draft,private,protected,deprecated,community,published'";
2121              $DB->query( "
2122                      INSERT INTO T_coll_user_perms( bloguser_blog_ID, bloguser_user_ID, bloguser_ismember,
2123                          bloguser_perm_poststatuses, bloguser_perm_delpost, bloguser_perm_edit_ts,
2124                          bloguser_perm_recycle_owncmts, bloguser_perm_vote_spam_cmts, bloguser_perm_cmtstatuses,
2125                          bloguser_perm_cats, bloguser_perm_properties,
2126                          bloguser_perm_media_upload, bloguser_perm_media_browse, bloguser_perm_media_change )
2127                      VALUES ( $this->ID, $current_User->ID, 1,
2128                          $perm_statuses, 1, 1, 1, 1, $perm_statuses, 1, 1, 1, 1, 1 )" );
2129          }
2130  
2131          /*
2132          if( $kind == 'forum' )
2133          {    // Set default group permissions for the Forum blog
2134              $GroupCache = & get_GroupCache();
2135              $groups_permissions = array();
2136              if( $GroupCache->get_by_ID( 1, false ) )
2137              {    // Check if "Administrators" group still exists
2138                  $groups_permissions[ 'admins' ] = "( $this->ID, 1, 1, 'published,deprecated,protected,private,draft', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 )";
2139              }
2140              if( $GroupCache->get_by_ID( 2, false ) )
2141              {    // Check if "Moderators" group still exists
2142                  $groups_permissions[ 'privileged' ] = "( $this->ID, 2, 1, 'published,deprecated,protected,private,draft', 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1 )";
2143              }
2144              if( $GroupCache->get_by_ID( 3, false ) )
2145              {    // Check if "Bloggers" group still exists
2146                  $groups_permissions[ 'bloggers' ] = "( $this->ID, 3, 1, 'published,deprecated,protected,private,draft', 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0 )";
2147              }
2148              if( $GroupCache->get_by_ID( 4, false ) )
2149              {    // Check if "Basic Users" group still exists
2150                  $groups_permissions[ 'users' ] = "( $this->ID, 4, 1, 'published', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 )";
2151              }
2152              if( $GroupCache->get_by_ID( 5, false ) )
2153              {    // Check if "Spam/Suspect Users" group still exists
2154                  $groups_permissions[ 'spam' ] = "( $this->ID, 5, 1, 'published,deprecated,protected,private,draft', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 )";
2155              }
2156              $DB->query( 'INSERT INTO T_coll_group_perms( bloggroup_blog_ID, bloggroup_group_ID, bloggroup_ismember,
2157                      bloggroup_perm_poststatuses, bloggroup_perm_delpost, bloggroup_perm_edit_ts,
2158                      bloggroup_perm_recycle_owncmts, bloggroup_perm_vote_spam_cmts, bloggroup_perm_draft_cmts, bloggroup_perm_publ_cmts, bloggroup_perm_depr_cmts,
2159                      bloggroup_perm_cats, bloggroup_perm_properties,
2160                      bloggroup_perm_media_upload, bloggroup_perm_media_browse, bloggroup_perm_media_change )
2161                  VALUES '.implode( ',', $groups_permissions ) );
2162          }*/
2163  
2164          // Create default category:
2165          load_class( 'chapters/model/_chapter.class.php', 'Chapter' );
2166          $edited_Chapter = new Chapter( NULL, $this->ID );
2167  
2168          $blog_urlname = $this->get( 'urlname' );
2169          $edited_Chapter->set( 'name', T_('Uncategorized') );
2170          $edited_Chapter->set( 'urlname', $blog_urlname.'-main' );
2171          $edited_Chapter->dbinsert();
2172  
2173          $Messages->add( T_('A default category has been created for this blog.'), 'success' );
2174  
2175          // ADD DEFAULT WIDGETS:
2176          load_funcs( 'widgets/_widgets.funcs.php' );
2177          insert_basic_widgets( $this->ID, false, $kind );
2178  
2179          $Messages->add( T_('Default widgets have been set-up for this blog.'), 'success' );
2180  
2181          $DB->commit();
2182  
2183          // set caching
2184          if( $Settings->get( 'newblog_cache_enabled' ) )
2185          {
2186              $result = set_cache_enabled( 'cache_enabled', true, $this->ID );
2187              if( $result != NULL )
2188              {
2189                  list( $status, $message ) = $result;
2190                  $Messages->add( $message, $status );
2191              }
2192          }
2193          $this->set_setting( 'cache_enabled_widgets', $Settings->get( 'newblog_cache_enabled_widget' ) );
2194  
2195          if( $this->get( 'advanced_perms' ) )
2196          {    // Display this warning if blog has the enabled advanced perms be default
2197              $Messages->add( sprintf(T_('ATTENTION: go to the <a %s>advanced group permissions for this blog/forum</a> in order to allow some user groups to post new topics into this forum.'), 'href='.$admin_url.'?ctrl=coll_settings&amp;tab=permgroup&amp;blog='.$this->ID ), 'warning' );
2198          }
2199  
2200          // Commit changes in cache:
2201          $BlogCache = & get_BlogCache();
2202          $BlogCache->add( $this );
2203      }
2204  
2205  
2206      /**
2207       * Update the DB based on previously recorded changes
2208       */
2209  	function dbupdate()
2210      {
2211          global $DB, $Plugins, $servertimenow;
2212  
2213          $DB->begin();
2214  
2215          parent::dbupdate();
2216  
2217          // if this blog settings was modified we need to invalidate this blog's page caches
2218          // this way all existing cached page on this blog will be regenerated during next display
2219          // TODO: Ideally we want to detect if the changes are minor/irrelevant to caching and not invalidate the page cache if not necessary.
2220          // In case of doubt (and for unknown changes), it's better to invalidate.
2221          $this->set_setting( 'last_invalidation_timestamp', $servertimenow );
2222  
2223          if( isset( $this->CollectionSettings ) )
2224          {
2225              $this->CollectionSettings->dbupdate();
2226          }
2227  
2228          $Plugins->trigger_event( 'AfterCollectionUpdate', $params = array( 'Blog' => & $this ) );
2229  
2230          $DB->commit();
2231  
2232          // Thick grained invalidation:
2233          // This collection has been modified, cached content depending on it should be invalidated:
2234          BlockCache::invalidate_key( 'coll_ID', $this->ID );
2235  
2236          // Fine grained invalidation:
2237          // EXPERIMENTAL: Below are more granular invalidation dates:
2238          BlockCache::invalidate_key( 'set_coll_ID', $this->ID ); // Settings have changed
2239          BlockCache::invalidate_key( 'set_coll_ID', 'any' ); // Settings of a have changed (for widgets tracking a change on ANY blog)
2240          // cont_coll_ID  // Content has not changed
2241      }
2242  
2243  
2244      /**
2245       * Delete a blog and dependencies from database
2246       *
2247       * Includes WAY TOO MANY requests because we try to be compatible with MySQL 3.23, bleh!
2248       *
2249       * @param boolean true if you want to echo progress
2250       */
2251  	function dbdelete( $echo = false )
2252      {
2253          global $DB, $Messages, $Plugins;
2254  
2255          // Try to obtain some serious time to do some serious processing (5 minutes)
2256          set_max_execution_time(300);
2257  
2258          // Note: No need to localize the status messages...
2259          if( $echo ) echo '<p>MySQL 3.23 compatibility mode!';
2260  
2261          $DB->begin();
2262  
2263          // Get list of cats that are going to be deleted (3.23)
2264          if( $echo ) echo '<br />Getting category list to delete... ';
2265          $cat_list = implode( ',', $DB->get_col( "
2266                  SELECT cat_ID
2267                    FROM T_categories
2268                   WHERE cat_blog_ID = $this->ID" ) );
2269  
2270          if( empty( $cat_list ) )
2271          { // There are no cats to delete
2272              if( $echo ) echo 'None!';
2273          }
2274          else
2275          { // Delete the cats & dependencies
2276  
2277              // Get list of posts that are going to be deleted (3.23)
2278              if( $echo ) echo '<br />Getting post list to delete... ';
2279              $post_list = implode( ',', $DB->get_col( "
2280                      SELECT postcat_post_ID
2281                        FROM T_postcats
2282                       WHERE postcat_cat_ID IN ($cat_list)" ) );
2283  
2284              if( empty( $post_list ) )
2285              { // There are no posts to delete
2286                  if( $echo ) echo 'None!';
2287              }
2288              else
2289              { // Delete the posts & dependencies
2290  
2291                  // TODO: There's also a constraint FK_post_parent_ID..
2292  
2293                  // Delete postcats
2294                  if( $echo ) echo '<br />Deleting post-categories... ';
2295                  $ret = $DB->query(    "DELETE FROM T_postcats
2296                                                              WHERE postcat_cat_ID IN ($cat_list)" );
2297                  if( $echo ) printf( '(%d rows)', $ret );
2298                  $Messages->add( T_('Deleted post-categories'), 'success' );
2299  
2300                  // Delete comments
2301                  if( $echo ) echo '<br />Deleting comments on blog\'s posts... ';
2302                  $comments_list = implode( ',', $DB->get_col( "
2303                          SELECT comment_ID
2304                            FROM T_comments
2305                           WHERE comment_post_ID IN ($post_list)" ) );
2306                  if( !empty( $comments_list ) )
2307                  {    // Delete the comments & dependencies
2308                      $DB->query( "DELETE FROM T_comments__votes
2309                                                  WHERE cmvt_cmt_ID IN ($comments_list)" );
2310                      $ret = $DB->query( "DELETE FROM T_comments
2311                                                              WHERE comment_post_ID IN ($post_list)" );
2312                  }
2313                  else
2314                  {    // No comments in this blog
2315                      $ret = 0;
2316                  }
2317                  if( $echo ) printf( '(%d rows)', $ret );
2318                  $Messages->add( T_('Deleted comments on blog\'s posts'), 'success' );
2319  
2320  
2321                  // Delete posts
2322                  if( $echo ) echo '<br />Deleting blog\'s posts... ';
2323                  $DB->query( "DELETE FROM T_items__itemtag
2324                                              WHERE itag_itm_ID IN ($post_list)" );
2325                  $DB->query( "DELETE FROM T_items__item_settings
2326                                              WHERE iset_item_ID IN ($post_list)" );
2327                  $DB->query( "DELETE FROM T_items__prerendering
2328                                              WHERE itpr_itm_ID IN ($post_list)" );
2329                  $DB->query( "DELETE FROM T_items__status
2330                                              WHERE pst_ID IN ($post_list)" );
2331                  $DB->query( "DELETE FROM T_items__subscriptions
2332                                              WHERE isub_item_ID IN ($post_list)" );
2333                  $DB->query( "DELETE FROM T_items__version
2334                                              WHERE iver_itm_ID IN ($post_list)" );
2335                  $DB->query( "DELETE FROM T_links
2336                                              WHERE link_itm_ID IN ($post_list)" );
2337                  $DB->query( "DELETE FROM T_slug
2338                                              WHERE slug_itm_ID IN ($post_list)" );
2339                  $ret = $DB->query( "DELETE FROM T_items__item
2340                                                              WHERE post_ID IN ($post_list)" );
2341                  if( $echo ) printf( '(%d rows)', $ret );
2342                  $Messages->add( T_('Deleted blog\'s posts'), 'success' );
2343  
2344              } // / are there posts?
2345  
2346              // Delete categories
2347              if( $echo ) echo '<br />Deleting blog\'s categories... ';
2348              $ret = $DB->query( "DELETE FROM T_categories
2349                                                      WHERE cat_blog_ID = $this->ID" );
2350              if( $echo ) printf( '(%d rows)', $ret );
2351              $Messages->add( T_('Deleted blog\'s categories'), 'success' );
2352  
2353          } // / are there cats?
2354  
2355          // Delete the blog cache folder - try to delete even if cache is disabled
2356          load_class( '_core/model/_pagecache.class.php', 'PageCache' );
2357          $PageCache = new PageCache( $this );
2358          $PageCache->cache_delete();
2359  
2360          // Delete the blog files/links from DB
2361          $DB->query( 'DELETE f, l, fv FROM T_files AS f
2362              LEFT JOIN T_links l ON l.link_file_ID = f.file_ID
2363              LEFT JOIN T_files__vote AS fv ON fv.fvot_file_ID = f.file_ID
2364                  WHERE f.file_root_type = "collection"
2365                    AND f.file_root_ID = '.$this->ID );
2366  
2367          // remember ID, because parent method resets it to 0
2368          $old_ID = $this->ID;
2369  
2370          // Delete main (blog) object:
2371          if( ! parent::dbdelete() )
2372          {
2373              $DB->rollback();
2374  
2375              $Messages->add( 'Blog has not been deleted.', 'error' );
2376              return false;
2377          }
2378  
2379          $DB->commit();
2380  
2381          // Delete blog's media folder recursively
2382          $FileRootCache = & get_FileRootCache();
2383          $root_directory = $FileRootCache->get_root_dir( 'collection', $old_ID );
2384          rmdir_r( $root_directory );
2385          $Messages->add( T_('Deleted blog\'s files'), 'success' );
2386  
2387          // re-set the ID for the Plugin event
2388          $this->ID = $old_ID;
2389          $Plugins->trigger_event( 'AfterCollectionDelete', $params = array( 'Blog' => & $this ) );
2390          $this->ID = 0;
2391  
2392          if( $echo ) echo '<br />Done.</p>';
2393      }
2394  
2395  
2396      /*
2397       * Template function: display name of blog
2398       *
2399       * Template tag
2400       */
2401  	function name( $params = array() )
2402      {
2403          // Make sure we are not missing any param:
2404          $params = array_merge( array(
2405                  'before'      => ' ',
2406                  'after'       => ' ',
2407                  'format'      => 'htmlbody',
2408              ), $params );
2409  
2410          if( !empty( $this->name ) )
2411          {
2412              echo $params['before'];
2413              $this->disp( 'name', $params['format'] );
2414              echo $params['after'];
2415          }
2416      }
2417  
2418  
2419      /*
2420       * Template function: display name of blog
2421       *
2422       * Template tag
2423       */
2424  	function tagline( $params = array() )
2425      {
2426          // Make sure we are not missing any param:
2427          $params = array_merge( array(
2428                  'before'      => ' ',
2429                  'after'       => ' ',
2430                  'format'      => 'htmlbody',
2431              ), $params );
2432  
2433          if( !empty( $this->tagline ) )
2434          {
2435              echo $params['before'];
2436              $this->disp( 'tagline', $params['format'] );
2437              echo $params['after'];
2438          }
2439      }
2440  
2441  
2442      /*
2443       * Template function: display name of blog
2444       *
2445       * Template tag
2446       */
2447  	function longdesc( $params = array() )
2448      {
2449          // Make sure we are not missing any param:
2450          $params = array_merge( array(
2451                  'before'      => ' ',
2452                  'after'       => ' ',
2453                  'format'      => 'htmlbody',
2454              ), $params );
2455  
2456          if( !empty( $this->longdesc ) )
2457          {
2458              echo $params['before'];
2459              $this->disp( 'longdesc', $params['format'] );
2460              echo $params['after'];
2461          }
2462      }
2463  
2464  
2465      /**
2466       * Get the name of the blog
2467       *
2468       * @return string
2469       */
2470  	function get_name()
2471      {
2472          return $this->name;
2473      }
2474  
2475      /**
2476       * Get the name of the blog limited by length
2477       *
2478       * @param integer Max length
2479       * @return string Limited name
2480       */
2481  	function get_maxlen_name( $maxlen = 50 )
2482      {
2483          return strmaxlen( $this->get_name(), $maxlen, NULL, 'raw' );
2484      }
2485  
2486  
2487      /**
2488       * Get short and long name of the blog
2489       *
2490       * @return string
2491       */
2492  	function get_extended_name()
2493      {
2494          $names = array();
2495  
2496          if( ! empty( $this->shortname ) )
2497          { // Short name
2498              $names[] = $this->shortname;
2499          }
2500  
2501          if( ! empty( $this->name ) )
2502          { // Title
2503              $names[] = $this->name;
2504          }
2505  
2506          return implode( ' - ', $names );
2507      }
2508  
2509  
2510      /*
2511       * Get the blog skin ID which correspond to the current session device
2512       *
2513       * @return integer skin ID
2514       */
2515  	function get_skin_ID()
2516      {
2517          global $Session;
2518  
2519          if( !empty( $Session ) )
2520          {
2521              if( $Session->is_mobile_session() )
2522              {
2523                  return $this->get_setting( 'mobile_skin_ID' );
2524              }
2525              if( $Session->is_tablet_session() )
2526              {
2527                  return $this->get_setting( 'tablet_skin_ID' );
2528              }
2529          }
2530  
2531          return $this->get_setting( 'normal_skin_ID' );
2532      }
2533  
2534  
2535      /**
2536       * Resolve user ID of owner
2537       *
2538       * @return User
2539       */
2540      function & get_owner_User()
2541      {
2542          if( !isset($this->owner_User) )
2543          {
2544              $UserCache = & get_UserCache();
2545              $this->owner_User = & $UserCache->get_by_ID($this->owner_user_ID);
2546          }
2547  
2548          return $this->owner_User;
2549      }
2550  
2551  
2552      /**
2553       * Template tag: display a link leading to the contact form for the owner of the current Blog.
2554       *
2555       * @param array (empty default array is provided for compatibility with v 1.10)
2556       */
2557  	function contact_link( $params = array() )
2558      {
2559          $owner_User = & $this->get_owner_User();
2560          if( ! $owner_User->get_msgform_possibility() )
2561          {
2562              return false;
2563          }
2564  
2565          // Make sure we are not missing any param:
2566          $params = array_merge( array(
2567                  'before'      => ' ',
2568                  'after'       => ' ',
2569                  'text'        => 'Contact', // Note: left untranslated, should be translated in skin anyway
2570                  'title'       => 'Send a message to the owner of this blog...',
2571              ), $params );
2572  
2573  
2574          echo $params['before'];
2575          echo '<a href="'.$this->get_contact_url(true).'" title="'.$params['title'].'" class="contact_link">'
2576                      .$params['text'].'</a>';
2577          echo $params['after'];
2578  
2579          return true;
2580      }
2581  
2582  
2583      /**
2584       * Template tag: display a link leading to the help page
2585       *
2586       * @param array
2587       */
2588  	function help_link( $params = array() )
2589      {
2590          // Make sure we are not missing any param:
2591          $params = array_merge( array(
2592                  'before'      => ' ',
2593                  'after'       => ' ',
2594                  'text'        => 'Help', // Note: left untranslated, should be translated in skin anyway
2595                  'title'       => '',
2596              ), $params );
2597  
2598  
2599          echo $params['before'];
2600          echo '<a href="'.$this->get('helpurl').'" title="'.$params['title'].'" class="help_link">'
2601                      .$params['text'].'</a>';
2602          echo $params['after'];
2603  
2604          return true;
2605      }
2606  
2607  
2608      /**
2609       * Template tag: display footer text for the current Blog.
2610       *
2611       * @param array
2612       * @return boolean true if something has been displayed
2613       */
2614  	function footer_text( $params )
2615      {
2616          // Make sure we are not missing any param:
2617          $params = array_merge( array(
2618                  'before'      => ' ',
2619                  'after'       => ' ',
2620              ), $params );
2621  
2622          $text = $this->get_setting( 'blog_footer_text' );
2623          $text = preg_replace_callback( '~\$([a-z]+)\$~', array( $this, 'replace_callback' ), $text );
2624  
2625          if( empty($text) )
2626          {
2627              return false;
2628          }
2629  
2630          echo $params['before'];
2631          echo $text;
2632          echo $params['after'];
2633  
2634          return true;
2635      }
2636  
2637  
2638      /**
2639       * Get URL of message form to contact the owner
2640       *
2641       * @param boolean do we want to redirect back to where we came from after message?
2642       */
2643  	function get_contact_url( $with_redirect = true )
2644      {
2645          $owner_User = & $this->get_owner_User();
2646          if( ! $owner_User->get_msgform_possibility() )
2647          { // user does not allow contact form
2648              return NULL;
2649          }
2650  
2651          $r = url_add_param( $this->get('msgformurl'), 'recipient_id='.$this->owner_user_ID );
2652  
2653          if( $with_redirect )
2654          {
2655              if( $owner_User->get_msgform_possibility() != 'login' )
2656              {
2657                  $r .= '&amp;redirect_to='
2658                      // The URL will be made relative on the next page (this is needed when $htsrv_url is on another domain! -- multiblog situation )
2659                      .rawurlencode( regenerate_url('','','','&') );
2660              }
2661              else
2662              {
2663                  $r .= '&amp;redirect_to='.rawurlencode( url_add_param( $this->gen_blogurl(), 'disp=msgform&recipient_id='.$owner_User->ID, '&' ) );
2664              }
2665          }
2666  
2667          return $r;
2668      }
2669  
2670  
2671      /**
2672       * Get SQL expression to match the list of aggregates collection IDs.
2673       *
2674       * This resolves as follows:
2675       *  - empty: current blog only
2676       *  - "*": all blogs (returns " 1 " as in "WHERE 1")
2677       *  - other: as present in DB
2678       *
2679       * @param string SQL field name
2680       * @return string e.g. "$field IN (1,5)". It will return " 1 ", when all blogs/cats are aggregated.
2681       */
2682  	function get_sql_where_aggregate_coll_IDs( $field )
2683      {
2684          $aggregate_coll_IDs = $this->get_setting('aggregate_coll_IDs');
2685          if( empty( $aggregate_coll_IDs ) )
2686          {    // We only want posts from the current blog:
2687              return " $field = $this->ID ";
2688          }
2689          elseif( $aggregate_coll_IDs == '*' )
2690          {
2691              return " 1 ";
2692          }
2693          else
2694          {    // We are aggregating posts from several blogs:
2695              return " $field IN ($aggregate_coll_IDs)";
2696          }
2697      }
2698  
2699  
2700      /**
2701       * Get # of posts for a given tag
2702       */
2703  	function get_tag_post_count( $tag )
2704      {
2705          global $DB;
2706  
2707          $sql = 'SELECT COUNT(DISTINCT itag_itm_ID)
2708                            FROM T_items__tag INNER JOIN T_items__itemtag ON itag_tag_ID = tag_ID
2709                                        INNER JOIN T_postcats ON itag_itm_ID = postcat_post_ID
2710                                        INNER JOIN T_categories ON postcat_cat_ID = cat_ID
2711                           WHERE cat_blog_ID = '.$this->ID.'
2712                                AND tag_name = '.$DB->quote( evo_strtolower($tag) );
2713  
2714          return $DB->get_var( $sql );
2715  
2716      }
2717  
2718  
2719      /**
2720       * Get the corresponding ajax form enabled setting
2721       *
2722       * @return boolean true if ajax form is enabled, false otherwise
2723       */
2724  	function get_ajax_form_enabled()
2725      {
2726          if( is_logged_in() )
2727          {
2728              return $this->get_setting( 'ajax_form_loggedin_enabled' );
2729          }
2730          return $this->get_setting( 'ajax_form_enabled' );
2731      }
2732  
2733  
2734      /**
2735       * Get timestamp value from the setting "timestamp_min"
2736       *
2737       * @return string
2738       */
2739  	function get_timestamp_min()
2740      {
2741          $timestamp_min = $this->get_setting( 'timestamp_min' );
2742  
2743          switch ( $timestamp_min )
2744          {
2745              case 'duration': // Set timestamp to show past posts after this date
2746                  $timestamp_value = time() - $this->get_setting( 'timestamp_min_duration' );
2747                  break;
2748              case 'no': // Don't show past posts
2749                  $timestamp_value = 'now';
2750                  break;
2751              case 'yes': // Show all past posts
2752              default:
2753                  $timestamp_value = '';
2754                  break;
2755          }
2756  
2757          return $timestamp_value;
2758      }
2759  
2760  
2761      /**
2762       * Get timestamp value from the setting "timestamp_max"
2763       *
2764       * @return string
2765       */
2766  	function get_timestamp_max()
2767      {
2768          $timestamp_max = $this->get_setting( 'timestamp_max' );
2769  
2770          switch ( $timestamp_max )
2771          {
2772              case 'duration': // Set timestamp to show future posts before this date
2773                  $timestamp_value = time() + $this->get_setting( 'timestamp_max_duration' );
2774                  break;
2775              case 'yes': // Show all future posts
2776                  $timestamp_value = '';
2777                  break;
2778              case 'no': // Don't show future posts
2779              default:
2780                  $timestamp_value = 'now';
2781                  break;
2782          }
2783  
2784          return $timestamp_value;
2785      }
2786  
2787  
2788      /**
2789       * Get url to write a new Post
2790       *
2791       * @param integer Category ID
2792       * @param string Post title
2793       * @param string Post urltitle
2794       * @param string Post type
2795       * @return string Url to write a new Post
2796       */
2797  	function get_write_item_url( $cat_ID = 0, $post_title = '', $post_urltitle = '', $post_type = '' )
2798      {
2799          $url = '';
2800  
2801          if( is_logged_in( false ) )
2802          {    // Only logged in and activated users can write a Post
2803              global $current_User;
2804  
2805              $ChapterCache = & get_ChapterCache();
2806              $selected_Chapter = $ChapterCache->get_by_ID( $cat_ID, false, false );
2807              if( $selected_Chapter && $selected_Chapter->lock )
2808              { // This category is locked, don't allow to create new post with this cat
2809                  return '';
2810              }
2811              if( $current_User->check_perm( 'blog_post_statuses', 'edit', false, $this->ID ) )
2812              {    // We have permission to add a post with at least one status:
2813                  if( $this->get_setting( 'in_skin_editing' ) && ! is_admin_page() )
2814                  {    // We have a mode 'In-skin editing' for the current Blog
2815                      // User must have a permission to publish a post in this blog
2816                      $cat_url_param = '';
2817                      if( $cat_ID > 0 )
2818                      {    // Link to create a Item with predefined category
2819                          $cat_url_param = '&amp;cat='.$cat_ID;
2820                      }
2821                      $url = url_add_param( $this->get( 'url' ), 'disp=edit'.$cat_url_param );
2822                  }
2823                  elseif( $current_User->check_perm( 'admin', 'restricted' ) )
2824                  {    // Edit a post from Back-office
2825                      global $admin_url;
2826                      $url = $admin_url.'?ctrl=items&amp;action=new&amp;blog='.$this->ID;
2827                      if( !empty( $cat_ID ) )
2828                      {    // Add category param to preselect category on the form
2829                          $url = url_add_param( $url, 'cat='.$cat_ID );
2830                      }
2831                  }
2832  
2833                  if( !empty( $post_title ) )
2834                  { // Append a post title
2835                      $url = url_add_param( $url, 'post_title='.$post_title );
2836                  }
2837                  if( !empty( $post_urltitle ) )
2838                  { // Append a post urltitle
2839                      $url = url_add_param( $url, 'post_urltitle='.$post_urltitle );
2840                  }
2841                  if( !empty( $post_type ) )
2842                  { // Append a post type
2843                      $url = url_add_param( $url, 'post_type='.$post_type );
2844                  }
2845              }
2846          }
2847  
2848          return $url;
2849      }
2850  
2851  
2852      /**
2853       * Get url to create a new Chapter
2854       *
2855       * @param integer Parent category ID
2856       * @return string Url to create a new Chapter
2857       */
2858  	function get_create_chapter_url( $cat_ID = 0 )
2859      {
2860          $url = '';
2861  
2862          if( is_logged_in( false ) )
2863          {    // Only logged in and activated users can write a Post
2864              global $current_User;
2865  
2866              if( $current_User->check_perm( 'admin', 'restricted' ) &&
2867                  $current_User->check_perm( 'blog_cats', 'edit', false, $this->ID ) )
2868              {    // Check permissions to create a new chapter in this blog
2869                  global $admin_url;
2870                  $url = $admin_url.'?ctrl=chapters&amp;action=new&amp;blog='.$this->ID;
2871                  if( !empty( $cat_ID ) )
2872                  {    // Add category param to preselect category on the form
2873                      $url = url_add_param( $url, 'cat_parent_ID='.$cat_ID );
2874                  }
2875              }
2876          }
2877  
2878          return $url;
2879      }
2880  
2881  
2882      /**
2883       * Country is visible for defining
2884       *
2885       * @return boolean TRUE if users can define a country for posts of current blog
2886       */
2887  	function country_visible()
2888      {
2889          return $this->get_setting( 'location_country' ) != 'hidden' || $this->region_visible();
2890      }
2891  
2892  
2893      /**
2894       * Region is visible for defining
2895       *
2896       * @return boolean TRUE if users can define a region for posts of current blog
2897       */
2898  	function region_visible()
2899      {
2900          return $this->get_setting( 'location_region' ) != 'hidden' || $this->subregion_visible();
2901      }
2902  
2903  
2904      /**
2905       * Subregion is visible for defining
2906       *
2907       * @return boolean TRUE if users can define a subregion for posts of current blog
2908       */
2909  	function subregion_visible()
2910      {
2911          return $this->get_setting( 'location_subregion' ) != 'hidden' || $this->city_visible();
2912      }
2913  
2914  
2915      /**
2916       * City is visible for defining
2917       *
2918       * @return boolean TRUE if users can define a city for posts of current blog
2919       */
2920  	function city_visible()
2921      {
2922          return $this->get_setting( 'location_city' ) != 'hidden';
2923      }
2924  }
2925  
2926  ?>

title

Description

title

Description

title

Description

title

title

Body