[ Index ]

PHP Cross Reference of phpBB-3.3.7-deutsch

title

Body

[close]

/includes/ -> functions_convert.php (source)

   1  <?php
   2  /**
   3  *
   4  * This file is part of the phpBB Forum Software package.
   5  *
   6  * @copyright (c) phpBB Limited <https://www.phpbb.com>
   7  * @license GNU General Public License, version 2 (GPL-2.0)
   8  *
   9  * For full copyright and license information, please see
  10  * the docs/CREDITS.txt file.
  11  *
  12  */
  13  
  14  /**
  15  * @ignore
  16  */
  17  if (!defined('IN_PHPBB'))
  18  {
  19      exit;
  20  }
  21  
  22  /**
  23  * Default avatar width/height
  24  * @ignore
  25  */
  26  define('DEFAULT_AVATAR_X', 80);
  27  define('DEFAULT_AVATAR_Y', 80);
  28  
  29  // Global functions - all functions can be used by convertors
  30  
  31  // SIMPLE FUNCTIONS
  32  
  33  /**
  34  * Return the preceding value
  35  */
  36  function dec($var)
  37  {
  38      return --$var;
  39  }
  40  
  41  /**
  42  * Return the next value
  43  */
  44  function inc($var)
  45  {
  46      return ++$var;
  47  }
  48  
  49  /**
  50  * Return whether the value is positive
  51  */
  52  function is_positive($n)
  53  {
  54      return ($n > 0) ? 1 : 0;
  55  }
  56  
  57  /**
  58  * Boolean inverse of the value
  59  */
  60  function not($var)
  61  {
  62      return ($var) ? 0 : 1;
  63  }
  64  
  65  /**
  66  * Convert a textual value to it's equivalent boolean value
  67  *
  68  * @param string $str String to convert (converts yes, on, y, 1 and true to boolean true)
  69  * @return boolean The equivalent value
  70  */
  71  function str_to_bool($str)
  72  {
  73      $str = strtolower($str);
  74      return ($str == 'yes' || $str == 'on' || $str == 'y' || $str == 'true' || $str == '1') ? true : false;
  75  }
  76  
  77  /**
  78  * Function to mimic php's empty() function (it is the same)
  79  */
  80  function is_empty($mixed)
  81  {
  82      return empty($mixed);
  83  }
  84  
  85  /**
  86  * Convert the name of a user's primary group to the appropriate equivalent phpBB group id
  87  *
  88  * @param string $status The name of the group
  89  * @return int The group_id corresponding to the equivalent group
  90  */
  91  function str_to_primary_group($status)
  92  {
  93      switch (ucfirst(strtolower($status)))
  94      {
  95          case 'Administrator':
  96              return get_group_id('administrators');
  97          break;
  98  
  99          case 'Super moderator':
 100          case 'Global moderator':
 101          case 'Moderator':
 102              return get_group_id('global_moderators');
 103          break;
 104  
 105          case 'Guest':
 106          case 'Anonymous':
 107              return get_group_id('guests');
 108          break;
 109  
 110          default:
 111              return get_group_id('registered');
 112          break;
 113      }
 114  }
 115  
 116  /**
 117  * Convert a boolean into the appropriate phpBB constant indicating whether the item is locked
 118  */
 119  function is_item_locked($bool)
 120  {
 121      return ($bool) ? ITEM_LOCKED : ITEM_UNLOCKED;
 122  }
 123  
 124  /**
 125  * Convert a value from days to seconds
 126  */
 127  function days_to_seconds($days)
 128  {
 129      return ($days * 86400);
 130  }
 131  
 132  /**
 133  * Determine whether a user is anonymous and return the appropriate new user_id
 134  */
 135  function is_user_anonymous($user_id)
 136  {
 137      return ($user_id > ANONYMOUS) ? $user_id : ANONYMOUS;
 138  }
 139  
 140  /**
 141  * Generate a key value based on existing values
 142  *
 143  * @param int $pad Amount to add to the maximum value
 144  * @return int Key value
 145  */
 146  function auto_id($pad = 0)
 147  {
 148      global $auto_id, $convert_row;
 149  
 150      if (!empty($convert_row['max_id']))
 151      {
 152          return $convert_row['max_id'] + $pad;
 153      }
 154  
 155      return $auto_id + $pad;
 156  }
 157  
 158  /**
 159  * Convert a boolean into the appropriate phpBB constant indicating whether the user is active
 160  */
 161  function set_user_type($user_active)
 162  {
 163      return ($user_active) ? USER_NORMAL : USER_INACTIVE;
 164  }
 165  
 166  /**
 167  * Convert a value from minutes to hours
 168  */
 169  function minutes_to_hours($minutes)
 170  {
 171      return ($minutes / 3600);
 172  }
 173  
 174  /**
 175  * Return the group_id for a given group name
 176  */
 177  function get_group_id($group_name)
 178  {
 179      global $db, $group_mapping;
 180  
 181      if (empty($group_mapping))
 182      {
 183          $sql = 'SELECT group_name, group_id
 184              FROM ' . GROUPS_TABLE;
 185          $result = $db->sql_query($sql);
 186  
 187          $group_mapping = array();
 188          while ($row = $db->sql_fetchrow($result))
 189          {
 190              $group_mapping[strtoupper($row['group_name'])] = (int) $row['group_id'];
 191          }
 192          $db->sql_freeresult($result);
 193      }
 194  
 195      if (!count($group_mapping))
 196      {
 197          add_default_groups();
 198          return get_group_id($group_name);
 199      }
 200  
 201      if (isset($group_mapping[strtoupper($group_name)]))
 202      {
 203          return $group_mapping[strtoupper($group_name)];
 204      }
 205  
 206      return $group_mapping['REGISTERED'];
 207  }
 208  
 209  /**
 210  * Convert a boolean into the appropriate phpBB constant indicating whether the topic is locked
 211  */
 212  function is_topic_locked($bool)
 213  {
 214      return (!empty($bool)) ? ITEM_LOCKED : ITEM_UNLOCKED;
 215  }
 216  
 217  /**
 218  * Generate a bbcode_uid value
 219  */
 220  function make_uid($timestamp)
 221  {
 222      static $last_timestamp, $last_uid;
 223  
 224      if (empty($last_timestamp) || $timestamp != $last_timestamp)
 225      {
 226          $last_uid = substr(base_convert(unique_id(), 16, 36), 0, BBCODE_UID_LEN);
 227      }
 228      $last_timestamp = $timestamp;
 229      return $last_uid;
 230  }
 231  
 232  
 233  /**
 234  * Validate a website address
 235  */
 236  function validate_website($url)
 237  {
 238      if ($url === 'http://')
 239      {
 240          return '';
 241      }
 242      else if (!preg_match('#^http[s]?://#i', $url) && strlen($url) > 0)
 243      {
 244          return 'http://' . $url;
 245      }
 246      return $url;
 247  }
 248  
 249  /**
 250  * Convert nulls to zeros for fields which allowed a NULL value in the source but not the destination
 251  */
 252  function null_to_zero($value)
 253  {
 254      return ($value === NULL) ? 0 : $value;
 255  }
 256  
 257  /**
 258  * Convert nulls to empty strings for fields which allowed a NULL value in the source but not the destination
 259  */
 260  function null_to_str($value)
 261  {
 262      return ($value === NULL) ? '' : $value;
 263  }
 264  
 265  // EXTENDED FUNCTIONS
 266  
 267  /**
 268  * Get old config value
 269  */
 270  function get_config_value($config_name)
 271  {
 272      static $convert_config;
 273  
 274      if (!isset($convert_config))
 275      {
 276          $convert_config = get_config();
 277      }
 278  
 279      if (!isset($convert_config[$config_name]))
 280      {
 281          return false;
 282      }
 283  
 284      return (empty($convert_config[$config_name])) ? '' : $convert_config[$config_name];
 285  }
 286  
 287  /**
 288  * Convert an IP address from the hexadecimal notation to normal dotted-quad notation
 289  */
 290  function decode_ip($int_ip)
 291  {
 292      if (!$int_ip)
 293      {
 294          return $int_ip;
 295      }
 296  
 297      $hexipbang = explode('.', chunk_split($int_ip, 2, '.'));
 298  
 299      // Any mod changing the way ips are stored? Then we are not able to convert and enter the ip "as is" to not "destroy" anything...
 300      if (count($hexipbang) < 4)
 301      {
 302          return $int_ip;
 303      }
 304  
 305      return hexdec($hexipbang[0]) . '.' . hexdec($hexipbang[1]) . '.' . hexdec($hexipbang[2]) . '.' . hexdec($hexipbang[3]);
 306  }
 307  
 308  /**
 309  * Reverse the encoding of wild-carded bans
 310  */
 311  function decode_ban_ip($int_ip)
 312  {
 313      return str_replace('255', '*', decode_ip($int_ip));
 314  }
 315  
 316  /**
 317  * Determine the MIME-type of a specified filename
 318  * This does not actually inspect the file, but simply uses the file extension
 319  */
 320  function mimetype($filename)
 321  {
 322      if (!preg_match('/\.([a-z0-9]+)$/i', $filename, $m))
 323      {
 324          return 'application/octet-stream';
 325      }
 326  
 327      switch (strtolower($m[1]))
 328      {
 329          case 'zip':        return 'application/zip';
 330          case 'jpeg':    return 'image/jpeg';
 331          case 'jpg':        return 'image/jpeg';
 332          case 'jpe':        return 'image/jpeg';
 333          case 'png':        return 'image/png';
 334          case 'gif':        return 'image/gif';
 335          case 'htm':
 336          case 'html':    return 'text/html';
 337          case 'tif':        return 'image/tiff';
 338          case 'tiff':    return 'image/tiff';
 339          case 'ras':        return 'image/x-cmu-raster';
 340          case 'pnm':        return 'image/x-portable-anymap';
 341          case 'pbm':        return 'image/x-portable-bitmap';
 342          case 'pgm':        return 'image/x-portable-graymap';
 343          case 'ppm':        return 'image/x-portable-pixmap';
 344          case 'rgb':        return 'image/x-rgb';
 345          case 'xbm':        return 'image/x-xbitmap';
 346          case 'xpm':        return 'image/x-xpixmap';
 347          case 'xwd':        return 'image/x-xwindowdump';
 348          case 'z':        return 'application/x-compress';
 349          case 'gtar':    return 'application/x-gtar';
 350          case 'tgz':        return 'application/x-gtar';
 351          case 'gz':        return 'application/x-gzip';
 352          case 'tar':        return 'application/x-tar';
 353          case 'xls':        return 'application/excel';
 354          case 'pdf':        return 'application/pdf';
 355          case 'ppt':        return 'application/powerpoint';
 356          case 'rm':        return 'application/vnd.rn-realmedia';
 357          case 'wma':        return 'audio/x-ms-wma';
 358          case 'swf':        return 'application/x-shockwave-flash';
 359          case 'ief':        return 'image/ief';
 360          case 'doc':
 361          case 'dot':
 362          case 'wrd':        return 'application/msword';
 363          case 'ai':
 364          case 'eps':
 365          case 'ps':        return 'application/postscript';
 366          case 'asc':
 367          case 'txt':
 368          case 'c':
 369          case 'cc':
 370          case 'h':
 371          case 'hh':
 372          case 'cpp':
 373          case 'hpp':
 374          case 'php':
 375          case 'php3':    return 'text/plain';
 376          default:         return 'application/octet-stream';
 377      }
 378  }
 379  
 380  /**
 381  * Obtain the dimensions of all remotely hosted avatars
 382  * This should only be called from execute_last
 383  * There can be significant network overhead if there are a large number of remote avatars
 384  * @todo Look at the option of allowing the user to decide whether this is called or to force the dimensions
 385  */
 386  function remote_avatar_dims()
 387  {
 388      global $db;
 389  
 390      $sql = 'SELECT user_id, user_avatar
 391          FROM ' . USERS_TABLE . '
 392          WHERE user_avatar_type = ' . AVATAR_REMOTE;
 393      $result = $db->sql_query($sql);
 394  
 395      $remote_avatars = array();
 396      while ($row = $db->sql_fetchrow($result))
 397      {
 398          $remote_avatars[(int) $row['user_id']] = $row['user_avatar'];
 399      }
 400      $db->sql_freeresult($result);
 401  
 402      foreach ($remote_avatars as $user_id => $avatar)
 403      {
 404          $width = (int) get_remote_avatar_dim($avatar, 0);
 405          $height = (int) get_remote_avatar_dim($avatar, 1);
 406  
 407          $sql = 'UPDATE ' . USERS_TABLE . '
 408              SET user_avatar_width = ' . (int) $width . ', user_avatar_height = ' . (int) $height . '
 409              WHERE user_id = ' . $user_id;
 410          $db->sql_query($sql);
 411      }
 412  }
 413  
 414  function import_avatar_gallery($gallery_name = '', $subdirs_as_galleries = false)
 415  {
 416      global $config, $convert, $user;
 417  
 418      $relative_path = empty($convert->convertor['source_path_absolute']);
 419  
 420      // check for trailing slash
 421      if (rtrim($convert->convertor['avatar_gallery_path'], '/') === '')
 422      {
 423          $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_GALLERY_PATH'], 'import_avatar_gallery()'), __LINE__, __FILE__);
 424      }
 425  
 426      $src_path = relative_base(path($convert->convertor['avatar_gallery_path'], $relative_path), $relative_path);
 427  
 428      if (is_dir($src_path))
 429      {
 430          // Do not die on failure... safe mode restrictions may be in effect.
 431          copy_dir($convert->convertor['avatar_gallery_path'], path($config['avatar_gallery_path']) . $gallery_name, !$subdirs_as_galleries, false, false, $relative_path);
 432  
 433          // only doing 1 level deep. (ibf 1.x)
 434          // notes: ibf has 2 tiers: directly in the avatar directory for base gallery (handled in the above statement), plus subdirs(handled below).
 435          // recursive subdirs ignored. -- i don't know if other forums support recursive galleries. if they do, this following code could be upgraded to be recursive.
 436          if ($subdirs_as_galleries)
 437          {
 438              $dirlist = array();
 439              if ($handle = @opendir($src_path))
 440              {
 441                  while ($entry = readdir($handle))
 442                  {
 443                      if ($entry[0] == '.' || $entry == 'CVS' || $entry == 'index.htm')
 444                      {
 445                          continue;
 446                      }
 447  
 448                      if (is_dir($src_path . $entry))
 449                      {
 450                          $dirlist[] = $entry;
 451                      }
 452                  }
 453                  closedir($handle);
 454              }
 455              else if ($dir = @dir($src_path))
 456              {
 457                  while ($entry = $dir->read())
 458                  {
 459                      if ($entry[0] == '.' || $entry == 'CVS' || $entry == 'index.htm')
 460                      {
 461                          continue;
 462                      }
 463  
 464                      if (is_dir($src_path . $entry))
 465                      {
 466                          $dirlist[] = $entry;
 467                      }
 468                  }
 469                  $dir->close();
 470              }
 471  
 472              for ($i = 0, $end = count($dirlist); $i < $end; ++$i)
 473              {
 474                  $dir = $dirlist[$i];
 475  
 476                  // Do not die on failure... safe mode restrictions may be in effect.
 477                  copy_dir(path($convert->convertor['avatar_gallery_path'], $relative_path) . $dir, path($config['avatar_gallery_path']) . $dir, true, false, false, $relative_path);
 478              }
 479          }
 480      }
 481  }
 482  
 483  function import_attachment_files($category_name = '')
 484  {
 485      global $config, $convert, $db, $user;
 486  
 487      $sql = 'SELECT config_value AS upload_path
 488          FROM ' . CONFIG_TABLE . "
 489          WHERE config_name = 'upload_path'";
 490      $result = $db->sql_query($sql);
 491      $config['upload_path'] = $db->sql_fetchfield('upload_path');
 492      $db->sql_freeresult($result);
 493  
 494      $relative_path = empty($convert->convertor['source_path_absolute']);
 495  
 496      if (empty($convert->convertor['upload_path']))
 497      {
 498          $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_UPLOAD_DIR'], 'import_attachment_files()'), __LINE__, __FILE__);
 499      }
 500  
 501      if (is_dir(relative_base(path($convert->convertor['upload_path'], $relative_path), $relative_path)))
 502      {
 503          copy_dir($convert->convertor['upload_path'], path($config['upload_path']) . $category_name, true, false, true, $relative_path);
 504      }
 505  }
 506  
 507  function attachment_forum_perms($forum_id)
 508  {
 509      if (!is_array($forum_id))
 510      {
 511          $forum_id = array($forum_id);
 512      }
 513  
 514      return serialize($forum_id);
 515  }
 516  
 517  // base64todec function
 518  // -> from php manual?
 519  function base64_unpack($string)
 520  {
 521      $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-';
 522      $base = strlen($chars);
 523  
 524      $length = strlen($string);
 525      $number = 0;
 526  
 527      for ($i = 1; $i <= $length; $i++)
 528      {
 529          $pos = $length - $i;
 530          $operand = strpos($chars, substr($string, $pos, 1));
 531          $exponent = pow($base, $i-1);
 532          $dec_value = $operand * $exponent;
 533          $number += $dec_value;
 534      }
 535  
 536      return $number;
 537  }
 538  
 539  function _import_check($config_var, $source, $use_target)
 540  {
 541      global $convert, $config;
 542  
 543      $result = array(
 544          'orig_source'    => $source,
 545          'copied'        => false,
 546          'relative_path'    => (empty($convert->convertor['source_path_absolute'])) ? true : false,
 547      );
 548  
 549      // copy file will prepend $phpBB_root_path
 550      $target = $config[$config_var] . '/' . utf8_basename(($use_target === false) ? $source : $use_target);
 551  
 552      if (!empty($convert->convertor[$config_var]) && strpos($source, $convert->convertor[$config_var]) !== 0)
 553      {
 554          $source = $convert->convertor[$config_var] . $source;
 555      }
 556  
 557      $result['source'] = $source;
 558  
 559      if (file_exists(relative_base($source, $result['relative_path'], __LINE__, __FILE__)))
 560      {
 561          $result['copied'] = copy_file($source, $target, false, false, $result['relative_path']);
 562      }
 563  
 564      if ($result['copied'])
 565      {
 566          $result['target'] = utf8_basename($target);
 567      }
 568      else
 569      {
 570          $result['target'] = ($use_target !== false) ? $result['orig_source'] : utf8_basename($target);
 571      }
 572  
 573      return $result;
 574  }
 575  
 576  function import_attachment($source, $use_target = false)
 577  {
 578      if (empty($source))
 579      {
 580          return '';
 581      }
 582  
 583      global $convert, $config, $user;
 584  
 585      // check for trailing slash
 586      if (rtrim($convert->convertor['upload_path'], '/') === '')
 587      {
 588          $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_UPLOAD_DIR'], 'import_attachment()'), __LINE__, __FILE__);
 589      }
 590  
 591      $result = _import_check('upload_path', $source, $use_target);
 592  
 593      if ($result['copied'])
 594      {
 595          // Thumbnails?
 596          if (is_array($convert->convertor['thumbnails']))
 597          {
 598              $thumb_dir = $convert->convertor['thumbnails'][0];
 599              $thumb_prefix = $convert->convertor['thumbnails'][1];
 600              $thumb_source = $thumb_dir . $thumb_prefix . utf8_basename($result['source']);
 601  
 602              if (strpos($thumb_source, $convert->convertor['upload_path']) !== 0)
 603              {
 604                  $thumb_source = $convert->convertor['upload_path'] . $thumb_source;
 605              }
 606              $thumb_target = $config['upload_path'] . '/thumb_' . $result['target'];
 607  
 608              if (file_exists(relative_base($thumb_source, $result['relative_path'], __LINE__, __FILE__)))
 609              {
 610                  copy_file($thumb_source, $thumb_target, false, false, $result['relative_path']);
 611              }
 612          }
 613      }
 614  
 615      return $result['target'];
 616  }
 617  
 618  function import_rank($source, $use_target = false)
 619  {
 620      if (empty($source))
 621      {
 622          return '';
 623      }
 624  
 625      global $convert, $user;
 626  
 627      if (!isset($convert->convertor['ranks_path']))
 628      {
 629          $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_RANKS_PATH'], 'import_rank()'), __LINE__, __FILE__);
 630      }
 631  
 632      $result = _import_check('ranks_path', $source, $use_target);
 633      return $result['target'];
 634  }
 635  
 636  function import_smiley($source, $use_target = false)
 637  {
 638      if (empty($source))
 639      {
 640          return '';
 641      }
 642  
 643      global $convert, $user;
 644  
 645      // check for trailing slash
 646      if (rtrim($convert->convertor['smilies_path'], '/') === '')
 647      {
 648          $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_SMILIES_PATH'], 'import_smiley()'), __LINE__, __FILE__);
 649      }
 650  
 651      $result = _import_check('smilies_path', $source, $use_target);
 652      return $result['target'];
 653  }
 654  
 655  /*
 656  */
 657  function import_avatar($source, $use_target = false, $user_id = false)
 658  {
 659      if (empty($source) || preg_match('#^https?:#i', $source) || preg_match('#blank\.(gif|png)$#i', $source))
 660      {
 661          return;
 662      }
 663  
 664      global $convert, $config, $user;
 665  
 666      // check for trailing slash
 667      if (rtrim($convert->convertor['avatar_path'], '/') === '')
 668      {
 669          $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_AVATAR_PATH'], 'import_avatar()'), __LINE__, __FILE__);
 670      }
 671  
 672      if ($use_target === false && $user_id !== false)
 673      {
 674          $use_target = $config['avatar_salt'] . '_' . $user_id . '.' . substr(strrchr($source, '.'), 1);
 675      }
 676  
 677      _import_check('avatar_path', $source, $use_target);
 678  
 679      return ((!empty($user_id)) ? $user_id : $use_target) . '.' . substr(strrchr($source, '.'), 1);
 680  }
 681  
 682  /**
 683  * @todo all image dimension functions below (there are a *lot*) should get revisited and converted to one or two functions (no more needed, really).
 684  */
 685  
 686  /**
 687  * Calculate the size of the specified image
 688  * Called from the following functions for calculating the size of specific image types
 689  */
 690  function get_image_dim($source)
 691  {
 692      if (empty($source))
 693      {
 694          return array(0, 0);
 695      }
 696  
 697      global $convert;
 698  
 699      $relative_path = empty($convert->convertor['source_path_absolute']);
 700  
 701      if (file_exists(relative_base($source, $relative_path)))
 702      {
 703          $image = relative_base($source, $relative_path);
 704          return @getimagesize($image);
 705      }
 706  
 707      return false;
 708  }
 709  
 710  /**
 711  * Obtain the width of the specified smilie
 712  */
 713  function get_smiley_width($src)
 714  {
 715      return get_smiley_dim($src, 0);
 716  }
 717  
 718  /**
 719  * Obtain the height of the specified smilie
 720  */
 721  function get_smiley_height($src)
 722  {
 723      return get_smiley_dim($src, 1);
 724  }
 725  
 726  /**
 727  * Obtain the size of the specified smilie (using the cache if possible) and cache the value
 728  */
 729  function get_smiley_dim($source, $axis)
 730  {
 731      if (empty($source))
 732      {
 733          return 15;
 734      }
 735  
 736      static $smiley_cache = array();
 737  
 738      if (isset($smiley_cache[$source]))
 739      {
 740          return $smiley_cache[$source][$axis];
 741      }
 742  
 743      global $convert, $user;
 744  
 745      $orig_source = $source;
 746  
 747      if (!isset($convert->convertor['smilies_path']))
 748      {
 749          $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_SMILIES_PATH'], 'get_smiley_dim()'), __LINE__, __FILE__);
 750      }
 751  
 752      if (!empty($convert->convertor['smilies_path']) && strpos($source, $convert->convertor['smilies_path']) !== 0)
 753      {
 754          $source = $convert->convertor['smilies_path'] . $source;
 755      }
 756  
 757      $smiley_cache[$orig_source] = get_image_dim($source);
 758  
 759      if (empty($smiley_cache[$orig_source]) || empty($smiley_cache[$orig_source][0]) || empty($smiley_cache[$orig_source][1]))
 760      {
 761          $smiley_cache[$orig_source] = array(15, 15);
 762          return 15;
 763      }
 764  
 765      return $smiley_cache[$orig_source][$axis];
 766  }
 767  
 768  /**
 769  * Obtain the width of the specified avatar
 770  */
 771  function get_avatar_width($src, $func = false, $arg1 = false, $arg2 = false)
 772  {
 773      return get_avatar_dim($src, 0, $func, $arg1, $arg2);
 774  }
 775  
 776  /**
 777  * Obtain the height of the specified avatar
 778  */
 779  function get_avatar_height($src, $func = false, $arg1 = false, $arg2 = false)
 780  {
 781      return get_avatar_dim($src, 1, $func, $arg1, $arg2);
 782  }
 783  
 784  /**
 785  */
 786  function get_avatar_dim($src, $axis, $func = false, $arg1 = false, $arg2 = false)
 787  {
 788      $avatar_type = AVATAR_UPLOAD;
 789  
 790      if ($func)
 791      {
 792          if ($arg1 || $arg2)
 793          {
 794              $ary = array($arg1);
 795  
 796              if ($arg2)
 797              {
 798                  $ary[] = $arg2;
 799              }
 800  
 801              $avatar_type = call_user_func_array($func, $ary);
 802          }
 803          else
 804          {
 805              $avatar_type = call_user_func($func);
 806          }
 807      }
 808  
 809      switch ($avatar_type)
 810      {
 811          case AVATAR_UPLOAD:
 812              return get_upload_avatar_dim($src, $axis);
 813          break;
 814  
 815          case AVATAR_GALLERY:
 816              return get_gallery_avatar_dim($src, $axis);
 817          break;
 818  
 819          case AVATAR_REMOTE:
 820              // see notes on this functions usage and (hopefully) model $func to avoid this accordingly
 821              return get_remote_avatar_dim($src, $axis);
 822          break;
 823  
 824          default:
 825              $default_x = (defined('DEFAULT_AVATAR_X_CUSTOM')) ? DEFAULT_AVATAR_X_CUSTOM : DEFAULT_AVATAR_X;
 826              $default_y = (defined('DEFAULT_AVATAR_Y_CUSTOM')) ? DEFAULT_AVATAR_Y_CUSTOM : DEFAULT_AVATAR_Y;
 827  
 828              return $axis ? $default_y : $default_x;
 829          break;
 830      }
 831  }
 832  
 833  /**
 834  * Obtain the size of the specified uploaded avatar (using the cache if possible) and cache the value
 835  */
 836  function get_upload_avatar_dim($source, $axis)
 837  {
 838      static $cachedims = false;
 839      static $cachekey = false;
 840  
 841      if (empty($source))
 842      {
 843          return 0;
 844      }
 845  
 846      if ($cachekey == $source)
 847      {
 848          return $cachedims[$axis];
 849      }
 850  
 851      if (substr($source, 0, 7) == 'upload:')
 852      {
 853          $source = substr($source, 7);
 854      }
 855  
 856      global $convert, $user;
 857  
 858      if (!isset($convert->convertor['avatar_path']))
 859      {
 860          $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_AVATAR_PATH'], 'get_upload_avatar_dim()'), __LINE__, __FILE__);
 861      }
 862  
 863      if (!empty($convert->convertor['avatar_path']) && strpos($source, $convert->convertor['avatar_path']) !== 0)
 864      {
 865          $source = path($convert->convertor['avatar_path'], empty($convert->convertor['source_path_absolute'])) . $source;
 866      }
 867  
 868      $cachedims = get_image_dim($source);
 869  
 870      if (empty($cachedims) || empty($cachedims[0]) || empty($cachedims[1]))
 871      {
 872          $default_x = (defined('DEFAULT_AVATAR_X_CUSTOM')) ? DEFAULT_AVATAR_X_CUSTOM : DEFAULT_AVATAR_X;
 873          $default_y = (defined('DEFAULT_AVATAR_Y_CUSTOM')) ? DEFAULT_AVATAR_Y_CUSTOM : DEFAULT_AVATAR_Y;
 874  
 875          $cachedims = array($default_x, $default_y);
 876      }
 877  
 878      return $cachedims[$axis];
 879  }
 880  
 881  /**
 882  * Obtain the size of the specified gallery avatar (using the cache if possible) and cache the value
 883  */
 884  function get_gallery_avatar_dim($source, $axis)
 885  {
 886      if (empty($source))
 887      {
 888          return 0;
 889      }
 890  
 891      static $avatar_cache = array();
 892  
 893      if (isset($avatar_cache[$source]))
 894      {
 895          return $avatar_cache[$source][$axis];
 896      }
 897  
 898      global $convert, $user;
 899  
 900      $orig_source = $source;
 901  
 902      if (!isset($convert->convertor['avatar_gallery_path']))
 903      {
 904          $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_GALLERY_PATH'], 'get_gallery_avatar_dim()'), __LINE__, __FILE__);
 905      }
 906  
 907      if (!empty($convert->convertor['avatar_gallery_path']) && strpos($source, $convert->convertor['avatar_gallery_path']) !== 0)
 908      {
 909          $source = path($convert->convertor['avatar_gallery_path'], empty($convert->convertor['source_path_absolute'])) . $source;
 910      }
 911  
 912      $avatar_cache[$orig_source] = get_image_dim($source);
 913  
 914      if (empty($avatar_cache[$orig_source]) || empty($avatar_cache[$orig_source][0]) || empty($avatar_cache[$orig_source][1]))
 915      {
 916          $default_x = (defined('DEFAULT_AVATAR_X_CUSTOM')) ? DEFAULT_AVATAR_X_CUSTOM : DEFAULT_AVATAR_X;
 917          $default_y = (defined('DEFAULT_AVATAR_Y_CUSTOM')) ? DEFAULT_AVATAR_Y_CUSTOM : DEFAULT_AVATAR_Y;
 918  
 919          $avatar_cache[$orig_source] = array($default_x, $default_y);
 920      }
 921  
 922      return $avatar_cache[$orig_source][$axis];
 923  }
 924  
 925  /**
 926  * Obtain the size of the specified remote avatar (using the cache if possible) and cache the value
 927  * Whilst it's unlikely that remote avatars will be duplicated, it is possible so caching seems the best option
 928  * This should only be called from a post processing step due to the possibility of network timeouts
 929  */
 930  function get_remote_avatar_dim($src, $axis)
 931  {
 932      if (empty($src))
 933      {
 934          return 0;
 935      }
 936  
 937      static $remote_avatar_cache = array();
 938  
 939      // an ugly hack: we assume that the dimensions of each remote avatar are accessed exactly twice (x and y)
 940      if (isset($remote_avatar_cache[$src]))
 941      {
 942          $retval = $remote_avatar_cache[$src][$axis];
 943          unset($remote_avatar_cache);
 944          return $retval;
 945      }
 946  
 947      $url_info = @parse_url($src);
 948      if (empty($url_info['host']))
 949      {
 950          return 0;
 951      }
 952      $host = $url_info['host'];
 953      $port = (isset($url_info['port'])) ? $url_info['port'] : 0;
 954      $protocol = (isset($url_info['scheme'])) ? $url_info['scheme'] : 'http';
 955      if (empty($port))
 956      {
 957          switch (strtolower($protocol))
 958          {
 959              case 'ftp':
 960                  $port = 21;
 961                  break;
 962  
 963              case 'https':
 964                  $port = 443;
 965                  break;
 966  
 967              default:
 968                  $port = 80;
 969          }
 970      }
 971  
 972      $timeout = @ini_get('default_socket_timeout');
 973      @ini_set('default_socket_timeout', 2);
 974  
 975      // We're just trying to reach the server to avoid timeouts
 976      $fp = @fsockopen($host, $port, $errno, $errstr, 1);
 977      if ($fp)
 978      {
 979          $remote_avatar_cache[$src] = @getimagesize($src);
 980          fclose($fp);
 981      }
 982  
 983      $default_x     = (defined('DEFAULT_AVATAR_X_CUSTOM')) ? DEFAULT_AVATAR_X_CUSTOM : DEFAULT_AVATAR_X;
 984      $default_y     = (defined('DEFAULT_AVATAR_Y_CUSTOM')) ? DEFAULT_AVATAR_Y_CUSTOM : DEFAULT_AVATAR_Y;
 985      $default     = array($default_x, $default_y);
 986  
 987      if (empty($remote_avatar_cache[$src]) || empty($remote_avatar_cache[$src][0]) || empty($remote_avatar_cache[$src][1]))
 988      {
 989          $remote_avatar_cache[$src] = $default;
 990      }
 991      else
 992      {
 993          // We trust gallery and uploaded avatars to conform to the size settings; we might have to adjust here
 994          if ($remote_avatar_cache[$src][0] > $default_x || $remote_avatar_cache[$src][1] > $default_y)
 995          {
 996              $bigger = ($remote_avatar_cache[$src][0] > $remote_avatar_cache[$src][1]) ? 0 : 1;
 997              $ratio = $default[$bigger] / $remote_avatar_cache[$src][$bigger];
 998              $remote_avatar_cache[$src][0] = (int) ($remote_avatar_cache[$src][0] * $ratio);
 999              $remote_avatar_cache[$src][1] = (int) ($remote_avatar_cache[$src][1] * $ratio);
1000          }
1001      }
1002  
1003      @ini_set('default_socket_timeout', $timeout);
1004      return $remote_avatar_cache[$src][$axis];
1005  }
1006  
1007  function set_user_options()
1008  {
1009      global $convert_row;
1010  
1011      // Key need to be set in row, else default value is chosen
1012      $keyoptions = array(
1013          'viewimg'        => array('bit' => 0, 'default' => 1),
1014          'viewflash'        => array('bit' => 1, 'default' => 1),
1015          'viewsmilies'    => array('bit' => 2, 'default' => 1),
1016          'viewsigs'        => array('bit' => 3, 'default' => 1),
1017          'viewavatars'    => array('bit' => 4, 'default' => 1),
1018          'viewcensors'    => array('bit' => 5, 'default' => 1),
1019          'attachsig'        => array('bit' => 6, 'default' => 0),
1020          'bbcode'        => array('bit' => 8, 'default' => 1),
1021          'smilies'        => array('bit' => 9, 'default' => 1),
1022          'sig_bbcode'    => array('bit' => 15, 'default' => 1),
1023          'sig_smilies'    => array('bit' => 16, 'default' => 1),
1024          'sig_links'        => array('bit' => 17, 'default' => 1),
1025      );
1026  
1027      $option_field = 0;
1028  
1029      foreach ($keyoptions as $key => $key_ary)
1030      {
1031          $value = (isset($convert_row[$key])) ? (int) $convert_row[$key] : $key_ary['default'];
1032  
1033          if ($value && !($option_field & 1 << $key_ary['bit']))
1034          {
1035              $option_field += 1 << $key_ary['bit'];
1036          }
1037      }
1038  
1039      return $option_field;
1040  }
1041  
1042  /**
1043  * Index messages on the fly as we convert them
1044  * @todo naderman, can you check that this works with the new search plugins as it's use is currently disabled (and thus untested)
1045  function search_indexing($message = '')
1046  {
1047      global $fulltext_search, $convert_row;
1048  
1049      if (!isset($convert_row['post_id']))
1050      {
1051          return;
1052      }
1053  
1054      if (!$message)
1055      {
1056          if (!isset($convert_row['message']))
1057          {
1058              return;
1059          }
1060  
1061          $message = $convert_row['message'];
1062      }
1063  
1064      $title = (isset($convert_row['title'])) ? $convert_row['title'] : '';
1065  
1066      $fulltext_search->index('post', $convert_row['post_id'], $message, $title, $convert_row['poster_id'], $convert_row['forum_id']);
1067  }
1068  */
1069  
1070  function make_unique_filename($filename)
1071  {
1072      if (!strlen($filename))
1073      {
1074          $filename = md5(unique_id()) . '.dat';
1075      }
1076      else if ($filename[0] == '.')
1077      {
1078          $filename = md5(unique_id()) . $filename;
1079      }
1080      else if (preg_match('/\.([a-z]+)$/i', $filename, $m))
1081      {
1082          $filename = preg_replace('/\.([a-z]+)$/i', '_' . md5(unique_id()) . '.\1', $filename);
1083      }
1084      else
1085      {
1086          $filename .= '_' . md5(unique_id()) . '.dat';
1087      }
1088  
1089      return $filename;
1090  }
1091  
1092  function words_unique(&$words)
1093  {
1094      reset($words);
1095      $return_array = array();
1096  
1097      $word = current($words);
1098      do
1099      {
1100          $return_array[$word] = $word;
1101      }
1102      while ($word = next($words));
1103  
1104      return $return_array;
1105  }
1106  
1107  /**
1108  * Adds a user to the specified group and optionally makes them a group leader
1109  * This function does not create the group if it does not exist and so should only be called after the groups have been created
1110  */
1111  function add_user_group($group_id, $user_id, $group_leader = false)
1112  {
1113      global $db;
1114  
1115      $sql = 'INSERT INTO ' . USER_GROUP_TABLE . ' ' . $db->sql_build_array('INSERT', array(
1116          'group_id'        => $group_id,
1117          'user_id'        => $user_id,
1118          'group_leader'    => ($group_leader) ? 1 : 0,
1119          'user_pending'    => 0));
1120      $db->sql_query($sql);
1121  }
1122  
1123  // STANDALONE FUNCTIONS
1124  
1125  /**
1126  * Add users to the pre-defined "special" groups
1127  *
1128  * @param string $group The name of the special group to add to
1129  * @param string $select_query An SQL query to retrieve the user(s) to add to the group
1130  * @param bool $use_src_db
1131  */
1132  function user_group_auth($group, $select_query, $use_src_db)
1133  {
1134      global $convert, $user, $db, $src_db, $same_db;
1135  
1136      if (!in_array($group, array('guests', 'registered', 'registered_coppa', 'global_moderators', 'administrators', 'bots')))
1137      {
1138          $convert->p_master->error(sprintf($user->lang['CONV_ERROR_WRONG_GROUP'], $group, 'user_group_auth()'), __LINE__, __FILE__, true);
1139          return;
1140      }
1141  
1142      $sql = 'SELECT group_id
1143          FROM ' . GROUPS_TABLE . "
1144          WHERE group_name = '" . $db->sql_escape(strtoupper($group)) . "'";
1145      $result = $db->sql_query($sql);
1146      $group_id = (int) $db->sql_fetchfield('group_id');
1147      $db->sql_freeresult($result);
1148  
1149      if (!$group_id)
1150      {
1151          $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_GROUP'], $group, 'user_group_auth()'), __LINE__, __FILE__, true);
1152          return;
1153      }
1154  
1155      if ($same_db || !$use_src_db)
1156      {
1157          $sql = 'INSERT INTO ' . USER_GROUP_TABLE . ' (user_id, group_id, user_pending)
1158              ' . str_replace('{' . strtoupper($group) . '}', $group_id . ', 0', $select_query);
1159          $db->sql_query($sql);
1160      }
1161      else
1162      {
1163          $result = $src_db->sql_query(str_replace('{' . strtoupper($group) . '}', $group_id . ' ', $select_query));
1164          while ($row = $src_db->sql_fetchrow($result))
1165          {
1166              // this might become quite a lot of INSERTS unfortunately
1167              $sql = 'INSERT INTO ' . USER_GROUP_TABLE . " (user_id, group_id, user_pending)
1168                  VALUES ({$row['user_id']}, $group_id, 0)";
1169              $db->sql_query($sql);
1170          }
1171          $src_db->sql_freeresult($result);
1172      }
1173  }
1174  
1175  /**
1176  * Retrieves configuration information from the source forum and caches it as an array
1177  * Both database and file driven configuration formats can be handled
1178  * (the type used is specified in $config_schema, see convert_phpbb20.php for more details)
1179  */
1180  function get_config()
1181  {
1182      static $convert_config;
1183      global $user;
1184  
1185      if (isset($convert_config))
1186      {
1187          return $convert_config;
1188      }
1189  
1190      global $src_db, $same_db;
1191      global $convert;
1192  
1193      if ($convert->config_schema['table_format'] != 'file')
1194      {
1195          if ($convert->mysql_convert && $same_db)
1196          {
1197              $src_db->sql_query("SET NAMES 'binary'");
1198          }
1199  
1200          $sql = 'SELECT * FROM ' . $convert->src_table_prefix . $convert->config_schema['table_name'];
1201          $result = $src_db->sql_query($sql);
1202          $row = $src_db->sql_fetchrow($result);
1203  
1204          if (!$row)
1205          {
1206              $convert->p_master->error($user->lang['CONV_ERROR_GET_CONFIG'], __LINE__, __FILE__);
1207          }
1208      }
1209  
1210      if (is_array($convert->config_schema['table_format']))
1211      {
1212          $convert_config = array();
1213          $key = key($convert->config_schema['table_format']);
1214          $val = current($convert->config_schema['table_format']);
1215  
1216          do
1217          {
1218              $convert_config[$row[$key]] = $row[$val];
1219          }
1220          while ($row = $src_db->sql_fetchrow($result));
1221          $src_db->sql_freeresult($result);
1222  
1223          if ($convert->mysql_convert && $same_db)
1224          {
1225              $src_db->sql_query("SET NAMES 'utf8'");
1226          }
1227      }
1228      else if ($convert->config_schema['table_format'] == 'file')
1229      {
1230          $filename = $convert->options['forum_path'] . '/' . $convert->config_schema['filename'];
1231          if (!file_exists($filename))
1232          {
1233              $convert->p_master->error($user->lang('FILE_NOT_FOUND', $filename), __LINE__, __FILE__);
1234          }
1235  
1236          if (isset($convert->config_schema['array_name']))
1237          {
1238              unset($convert->config_schema['array_name']);
1239          }
1240  
1241          $convert_config = extract_variables_from_file($filename);
1242          if (!empty($convert->config_schema['array_name']))
1243          {
1244              $convert_config = $convert_config[$convert->config_schema['array_name']];
1245          }
1246      }
1247      else
1248      {
1249          $convert_config = $row;
1250          if ($convert->mysql_convert && $same_db)
1251          {
1252              $src_db->sql_query("SET NAMES 'utf8'");
1253          }
1254      }
1255  
1256      if (!count($convert_config))
1257      {
1258          $convert->p_master->error($user->lang['CONV_ERROR_CONFIG_EMPTY'], __LINE__, __FILE__);
1259      }
1260  
1261      return $convert_config;
1262  }
1263  
1264  /**
1265  * Transfers the relevant configuration information from the source forum
1266  * The mapping of fields is specified in $config_schema, see convert_phpbb20.php for more details
1267  */
1268  function restore_config($schema)
1269  {
1270      global $config;
1271  
1272      $convert_config = get_config();
1273  
1274      foreach ($schema['settings'] as $config_name => $src)
1275      {
1276          if (preg_match('/(.*)\((.*)\)/', $src, $m))
1277          {
1278              $var = (empty($m[2]) || empty($convert_config[$m[2]])) ? "''" : "'" . addslashes($convert_config[$m[2]]) . "'";
1279              $exec = '$config_value = ' . $m[1] . '(' . $var . ');';
1280              // @codingStandardsIgnoreStart
1281              eval($exec);
1282              // @codingStandardsIgnoreEnd
1283          }
1284          else
1285          {
1286              if ($schema['table_format'] != 'file' || empty($schema['array_name']))
1287              {
1288                  $config_value = (isset($convert_config[$src])) ? $convert_config[$src] : '';
1289              }
1290              else if (!empty($schema['array_name']))
1291              {
1292                  $src_ary = $schema['array_name'];
1293                  $config_value = (isset($convert_config[$src_ary][$src])) ? $convert_config[$src_ary][$src] : '';
1294              }
1295          }
1296  
1297          if ($config_value !== '')
1298          {
1299              // Most are...
1300              if (is_string($config_value))
1301              {
1302                  $config_value = truncate_string(utf8_htmlspecialchars($config_value), 255, 255, false);
1303              }
1304  
1305              $config->set($config_name, $config_value);
1306          }
1307      }
1308  }
1309  
1310  /**
1311  * Update the count of PM's in custom folders for all users
1312  */
1313  function update_folder_pm_count()
1314  {
1315      global $db;
1316  
1317      $sql = 'SELECT user_id, folder_id, COUNT(msg_id) as num_messages
1318          FROM ' . PRIVMSGS_TO_TABLE . '
1319          WHERE folder_id NOT IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ', ' . PRIVMSGS_INBOX . ', ' . PRIVMSGS_OUTBOX . ', ' . PRIVMSGS_SENTBOX . ')
1320          GROUP BY folder_id, user_id';
1321      $result = $db->sql_query($sql);
1322  
1323      while ($row = $db->sql_fetchrow($result))
1324      {
1325          $db->sql_query('UPDATE ' . PRIVMSGS_FOLDER_TABLE . ' SET pm_count = ' . $row['num_messages'] . '
1326              WHERE user_id = ' . $row['user_id'] . ' AND folder_id = ' . $row['folder_id']);
1327      }
1328      $db->sql_freeresult($result);
1329  }
1330  
1331  // Functions mainly used by the main convertor script
1332  
1333  function path($path, $path_relative = true)
1334  {
1335      if ($path === false)
1336      {
1337          return '';
1338      }
1339  
1340      if (substr($path, -1) != '/')
1341      {
1342          $path .= '/';
1343      }
1344  
1345      if (!$path_relative)
1346      {
1347          return $path;
1348      }
1349  
1350      if (substr($path, 0, 1) == '/')
1351      {
1352          $path = substr($path, 1);
1353      }
1354  
1355      return $path;
1356  }
1357  
1358  /**
1359  * Extract the variables defined in a configuration file
1360  * @todo As noted by Xore we need to look at this from a security perspective
1361  */
1362  function extract_variables_from_file($_filename)
1363  {
1364      include($_filename);
1365  
1366      $vars = get_defined_vars();
1367      unset($vars['_filename']);
1368  
1369      return $vars;
1370  }
1371  
1372  function get_path($src_path, $src_url, $test_file)
1373  {
1374      global $phpbb_root_path, $phpEx;
1375  
1376      $board_config = get_config();
1377  
1378      $test_file = preg_replace('/\.php$/i', ".$phpEx", $test_file);
1379      $src_path = path($src_path);
1380  
1381      if (@file_exists($phpbb_root_path . $src_path . $test_file))
1382      {
1383          return $src_path;
1384      }
1385  
1386      if (!empty($src_url) && !empty($board_config['server_name']))
1387      {
1388          if (!preg_match('#https?://([^/]+)(.*)#i', $src_url, $m))
1389          {
1390              return false;
1391          }
1392  
1393          if ($m[1] != $board_config['server_name'])
1394          {
1395              return false;
1396          }
1397  
1398          $url_parts = explode('/', $m[2]);
1399          if (substr($src_url, -1) != '/')
1400          {
1401              if (preg_match('/.*\.([a-z0-9]{3,4})$/i', $url_parts[count($url_parts) - 1]))
1402              {
1403                  $url_parts[count($url_parts) - 1] = '';
1404              }
1405              else
1406              {
1407                  $url_parts[] = '';
1408              }
1409          }
1410  
1411          $script_path = $board_config['script_path'];
1412          if (substr($script_path, -1) == '/')
1413          {
1414              $script_path = substr($script_path, 0, -1);
1415          }
1416  
1417          $path_array = array();
1418  
1419          $phpbb_parts = explode('/', $script_path);
1420          for ($i = 0, $end = count($url_parts); $i < $end; ++$i)
1421          {
1422              if ($i < count($phpbb_parts[$i]) && $url_parts[$i] == $phpbb_parts[$i])
1423              {
1424                  $path_array[] = $url_parts[$i];
1425                  unset($url_parts[$i]);
1426              }
1427              else
1428              {
1429                  $path = '';
1430                  for ($j = $i, $end2 = count($phpbb_parts); $j < $end2; ++$j)
1431                  {
1432                      $path .= '../';
1433                  }
1434                  $path .= implode('/', $url_parts);
1435                  break;
1436              }
1437          }
1438  
1439          if (!empty($path))
1440          {
1441              if (@file_exists($phpbb_root_path . $path . $test_file))
1442              {
1443                  return $path;
1444              }
1445          }
1446      }
1447  
1448      return false;
1449  }
1450  
1451  function compare_table($tables, $tablename, &$prefixes)
1452  {
1453      for ($i = 0, $table_size = count($tables); $i < $table_size; ++$i)
1454      {
1455          if (preg_match('/(.*)' . $tables[$i] . '$/', $tablename, $m))
1456          {
1457              if (empty($m[1]))
1458              {
1459                  $m[1] = '*';
1460              }
1461  
1462              if (isset($prefixes[$m[1]]))
1463              {
1464                  $prefixes[$m[1]]++;
1465              }
1466              else
1467              {
1468                  $prefixes[$m[1]] = 1;
1469              }
1470          }
1471      }
1472  }
1473  
1474  /**
1475  * Grant permissions to a specified user or group
1476  *
1477  * @param string $ug_type user|group|user_role|group_role
1478  * @param mixed $forum_id forum ids (array|int|0) -> 0 == all forums
1479  * @param mixed $ug_id [int] user_id|group_id : [string] usergroup name
1480  * @param mixed $acl_list [string] acl entry : [array] acl entries : [string] role entry
1481  * @param int $setting ACL_YES|ACL_NO|ACL_NEVER
1482  */
1483  function mass_auth($ug_type, $forum_id, $ug_id, $acl_list, $setting = ACL_NO)
1484  {
1485      global $db;
1486      static $acl_option_ids, $group_ids;
1487  
1488      if (($ug_type == 'group' || $ug_type == 'group_role') && is_string($ug_id))
1489      {
1490          if (!isset($group_ids[$ug_id]))
1491          {
1492              $sql = 'SELECT group_id
1493                  FROM ' . GROUPS_TABLE . "
1494                  WHERE group_name = '" . $db->sql_escape(strtoupper($ug_id)) . "'";
1495              $result = $db->sql_query_limit($sql, 1);
1496              $id = (int) $db->sql_fetchfield('group_id');
1497              $db->sql_freeresult($result);
1498  
1499              if (!$id)
1500              {
1501                  return;
1502              }
1503  
1504              $group_ids[$ug_id] = $id;
1505          }
1506  
1507          $ug_id = (int) $group_ids[$ug_id];
1508      }
1509  
1510      $table = ($ug_type == 'user' || $ug_type == 'user_role') ? ACL_USERS_TABLE : ACL_GROUPS_TABLE;
1511      $id_field = ($ug_type == 'user' || $ug_type == 'user_role') ? 'user_id' : 'group_id';
1512  
1513      // Role based permissions are the simplest to handle so check for them first
1514      if ($ug_type == 'user_role' || $ug_type == 'group_role')
1515      {
1516          if (is_numeric($forum_id))
1517          {
1518              $sql = 'SELECT role_id
1519                  FROM ' . ACL_ROLES_TABLE . "
1520                  WHERE role_name = 'ROLE_" . $db->sql_escape($acl_list) . "'";
1521              $result = $db->sql_query_limit($sql, 1);
1522              $row = $db->sql_fetchrow($result);
1523              $db->sql_freeresult($result);
1524  
1525              // If we have no role id there is something wrong here
1526              if ($row)
1527              {
1528                  $sql = "INSERT INTO $table ($id_field, forum_id, auth_role_id) VALUES ($ug_id, $forum_id, " . $row['role_id'] . ')';
1529                  $db->sql_query($sql);
1530              }
1531          }
1532  
1533          return;
1534      }
1535  
1536      // Build correct parameters
1537      $auth = array();
1538  
1539      if (!is_array($acl_list))
1540      {
1541          $auth = array($acl_list => $setting);
1542      }
1543      else
1544      {
1545          foreach ($acl_list as $auth_option)
1546          {
1547              $auth[$auth_option] = $setting;
1548          }
1549      }
1550      unset($acl_list);
1551  
1552      if (!is_array($forum_id))
1553      {
1554          $forum_id = array($forum_id);
1555      }
1556  
1557      // Set any flags as required
1558      foreach ($auth as $auth_option => $acl_setting)
1559      {
1560          $flag = substr($auth_option, 0, strpos($auth_option, '_') + 1);
1561          if (empty($auth[$flag]))
1562          {
1563              $auth[$flag] = $acl_setting;
1564          }
1565      }
1566  
1567      if (!is_array($acl_option_ids) || empty($acl_option_ids))
1568      {
1569          $sql = 'SELECT auth_option_id, auth_option
1570              FROM ' . ACL_OPTIONS_TABLE;
1571          $result = $db->sql_query($sql);
1572  
1573          while ($row = $db->sql_fetchrow($result))
1574          {
1575              $acl_option_ids[$row['auth_option']] = $row['auth_option_id'];
1576          }
1577          $db->sql_freeresult($result);
1578      }
1579  
1580      $sql_forum = 'AND ' . $db->sql_in_set('a.forum_id', array_map('intval', $forum_id), false, true);
1581  
1582      $sql = ($ug_type == 'user') ? 'SELECT o.auth_option_id, o.auth_option, a.forum_id, a.auth_setting FROM ' . ACL_USERS_TABLE . ' a, ' . ACL_OPTIONS_TABLE . " o WHERE a.auth_option_id = o.auth_option_id $sql_forum AND a.user_id = $ug_id" : 'SELECT o.auth_option_id, o.auth_option, a.forum_id, a.auth_setting FROM ' . ACL_GROUPS_TABLE . ' a, ' . ACL_OPTIONS_TABLE . " o WHERE a.auth_option_id = o.auth_option_id $sql_forum AND a.group_id = $ug_id";
1583      $result = $db->sql_query($sql);
1584  
1585      $cur_auth = array();
1586      while ($row = $db->sql_fetchrow($result))
1587      {
1588          $cur_auth[$row['forum_id']][$row['auth_option_id']] = $row['auth_setting'];
1589      }
1590      $db->sql_freeresult($result);
1591  
1592      $sql_ary = array();
1593      foreach ($forum_id as $forum)
1594      {
1595          foreach ($auth as $auth_option => $setting)
1596          {
1597              $auth_option_id = $acl_option_ids[$auth_option];
1598  
1599              if (!$auth_option_id)
1600              {
1601                  continue;
1602              }
1603  
1604              switch ($setting)
1605              {
1606                  case ACL_NO:
1607                      if (isset($cur_auth[$forum][$auth_option_id]))
1608                      {
1609                          $sql_ary['delete'][] = "DELETE FROM $table
1610                              WHERE forum_id = $forum
1611                                  AND auth_option_id = $auth_option_id
1612                                  AND $id_field = $ug_id";
1613                      }
1614                  break;
1615  
1616                  default:
1617                      if (!isset($cur_auth[$forum][$auth_option_id]))
1618                      {
1619                          $sql_ary['insert'][] = "$ug_id, $forum, $auth_option_id, $setting";
1620                      }
1621                      else if ($cur_auth[$forum][$auth_option_id] != $setting)
1622                      {
1623                          $sql_ary['update'][] = "UPDATE " . $table . "
1624                              SET auth_setting = $setting
1625                              WHERE $id_field = $ug_id
1626                                  AND forum_id = $forum
1627                                  AND auth_option_id = $auth_option_id";
1628                      }
1629              }
1630          }
1631      }
1632      unset($cur_auth);
1633  
1634      $sql = '';
1635      foreach ($sql_ary as $sql_type => $sql_subary)
1636      {
1637          switch ($sql_type)
1638          {
1639              case 'insert':
1640                  switch ($db->get_sql_layer())
1641                  {
1642                      case 'sqlite3':
1643                      case 'mssqlnative':
1644                          $sql = implode(' UNION ALL ', preg_replace('#^(.*?)$#', 'SELECT \1', $sql_subary));
1645                      break;
1646  
1647                      default:
1648                          foreach ($sql_subary as $sql)
1649                          {
1650                              $sql = "INSERT INTO $table ($id_field, forum_id, auth_option_id, auth_setting) VALUES ($sql)";
1651                              $db->sql_query($sql);
1652                              $sql = '';
1653                          }
1654                  }
1655  
1656                  if ($sql != '')
1657                  {
1658                      $sql = "INSERT INTO $table ($id_field, forum_id, auth_option_id, auth_setting) $sql";
1659                      $db->sql_query($sql);
1660                  }
1661              break;
1662  
1663              case 'update':
1664              case 'delete':
1665                  foreach ($sql_subary as $sql)
1666                  {
1667                      $db->sql_query($sql);
1668                      $sql = '';
1669                  }
1670              break;
1671          }
1672          unset($sql_ary[$sql_type]);
1673      }
1674      unset($sql_ary);
1675  
1676  }
1677  
1678  /**
1679  * Update the count of unread private messages for all users
1680  */
1681  function update_unread_count()
1682  {
1683      global $db;
1684  
1685      $sql = 'SELECT user_id, COUNT(msg_id) as num_messages
1686          FROM ' . PRIVMSGS_TO_TABLE . '
1687          WHERE pm_unread = 1
1688              AND folder_id <> ' . PRIVMSGS_OUTBOX . '
1689          GROUP BY user_id';
1690      $result = $db->sql_query($sql);
1691  
1692      while ($row = $db->sql_fetchrow($result))
1693      {
1694          $db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_unread_privmsg = ' . $row['num_messages'] . '
1695              WHERE user_id = ' . $row['user_id']);
1696      }
1697      $db->sql_freeresult($result);
1698  }
1699  
1700  /**
1701  * Add any of the pre-defined "special" groups which are missing from the database
1702  */
1703  function add_default_groups()
1704  {
1705      global $db;
1706  
1707      $default_groups = array(
1708          'GUESTS'            => array('', 0, 0),
1709          'REGISTERED'        => array('', 0, 0),
1710          'REGISTERED_COPPA'    => array('', 0, 0),
1711          'GLOBAL_MODERATORS'    => array('00AA00', 2, 0),
1712          'ADMINISTRATORS'    => array('AA0000', 1, 1),
1713          'BOTS'                => array('9E8DA7', 0, 0),
1714          'NEWLY_REGISTERED'        => array('', 0, 0),
1715      );
1716  
1717      $sql = 'SELECT *
1718          FROM ' . GROUPS_TABLE . '
1719          WHERE ' . $db->sql_in_set('group_name', array_keys($default_groups));
1720      $result = $db->sql_query($sql);
1721  
1722      while ($row = $db->sql_fetchrow($result))
1723      {
1724          unset($default_groups[strtoupper($row['group_name'])]);
1725      }
1726      $db->sql_freeresult($result);
1727  
1728      $sql_ary = array();
1729  
1730      foreach ($default_groups as $name => $data)
1731      {
1732          $sql_ary[] = array(
1733              'group_name'            => (string) $name,
1734              'group_desc'            => '',
1735              'group_desc_uid'        => '',
1736              'group_desc_bitfield'    => '',
1737              'group_type'            => GROUP_SPECIAL,
1738              'group_colour'            => (string) $data[0],
1739              'group_legend'            => (int) $data[1],
1740              'group_founder_manage'    => (int) $data[2],
1741          );
1742      }
1743  
1744      if (count($sql_ary))
1745      {
1746          $db->sql_multi_insert(GROUPS_TABLE, $sql_ary);
1747      }
1748  }
1749  
1750  function add_groups_to_teampage()
1751  {
1752      global $db;
1753  
1754      $teampage_groups = array(
1755          'ADMINISTRATORS'    => 1,
1756          'GLOBAL_MODERATORS'    => 2,
1757      );
1758  
1759      $sql = 'SELECT *
1760          FROM ' . GROUPS_TABLE . '
1761          WHERE ' . $db->sql_in_set('group_name', array_keys($teampage_groups));
1762      $result = $db->sql_query($sql);
1763  
1764      $teampage_ary = array();
1765      while ($row = $db->sql_fetchrow($result))
1766      {
1767          $teampage_ary[] = array(
1768              'group_id'                => (int) $row['group_id'],
1769              'teampage_name'            => '',
1770              'teampage_position'        => (int) $teampage_groups[$row['group_name']],
1771              'teampage_parent'        => 0,
1772          );
1773      }
1774      $db->sql_freeresult($result);
1775  
1776      if (count($teampage_ary))
1777      {
1778          $db->sql_multi_insert(TEAMPAGE_TABLE, $teampage_ary);
1779      }
1780  }
1781  
1782  
1783  /**
1784  * Sync post count. We might need to do this in batches.
1785  */
1786  function sync_post_count($offset, $limit)
1787  {
1788      global $db;
1789      $sql = 'SELECT COUNT(post_id) AS num_posts, poster_id
1790              FROM ' . POSTS_TABLE . '
1791              WHERE post_postcount = 1
1792                  AND post_visibility = ' . ITEM_APPROVED . '
1793              GROUP BY poster_id
1794              ORDER BY poster_id';
1795      $result = $db->sql_query_limit($sql, $limit, $offset);
1796  
1797      while ($row = $db->sql_fetchrow($result))
1798      {
1799          $db->sql_query('UPDATE ' . USERS_TABLE . " SET user_posts = {$row['num_posts']} WHERE user_id = {$row['poster_id']}");
1800      }
1801      $db->sql_freeresult($result);
1802  }
1803  
1804  /**
1805  * Add the search bots into the database
1806  * This code should be used in execute_last if the source database did not have bots
1807  * If you are converting bots this function should not be called
1808  * @todo We might want to look at sharing the bot list between the install code and this code for consistancy
1809  */
1810  function add_bots()
1811  {
1812      global $db, $convert, $user, $config, $phpbb_root_path, $phpEx;
1813  
1814      $db->sql_query($convert->truncate_statement . BOTS_TABLE);
1815  
1816      $sql = 'SELECT group_id FROM ' . GROUPS_TABLE . " WHERE group_name = 'BOTS'";
1817      $result = $db->sql_query($sql);
1818      $group_id = (int) $db->sql_fetchfield('group_id', false, $result);
1819      $db->sql_freeresult($result);
1820  
1821      if (!$group_id)
1822      {
1823          add_default_groups();
1824  
1825          $sql = 'SELECT group_id FROM ' . GROUPS_TABLE . " WHERE group_name = 'BOTS'";
1826          $result = $db->sql_query($sql);
1827          $group_id = (int) $db->sql_fetchfield('group_id', false, $result);
1828          $db->sql_freeresult($result);
1829  
1830          if (!$group_id)
1831          {
1832              global $install;
1833              $install->error($user->lang['CONV_ERROR_INCONSISTENT_GROUPS'], __LINE__, __FILE__);
1834          }
1835      }
1836  
1837      $bots = array(
1838          'AdsBot [Google]'            => array('AdsBot-Google', ''),
1839          'Ahrefs [Bot]'                => array('AhrefsBot/', ''),
1840          'Alexa [Bot]'                => array('ia_archiver', ''),
1841          'Alta Vista [Bot]'            => array('Scooter/', ''),
1842          'Amazon [Bot]'                => array('Amazonbot/', ''),
1843          'Ask Jeeves [Bot]'            => array('Ask Jeeves', ''),
1844          'Baidu [Spider]'            => array('Baiduspider', ''),
1845          'Bing [Bot]'                => array('bingbot/', ''),
1846          'DuckDuckGo [Bot]'            => array('DuckDuckBot/', ''),
1847          'Exabot [Bot]'                => array('Exabot/', ''),
1848          'FAST Enterprise [Crawler]'    => array('FAST Enterprise Crawler', ''),
1849          'FAST WebCrawler [Crawler]'    => array('FAST-WebCrawler/', ''),
1850          'Francis [Bot]'                => array('http://www.neomo.de/', ''),
1851          'Gigabot [Bot]'                => array('Gigabot/', ''),
1852          'Google Adsense [Bot]'        => array('Mediapartners-Google', ''),
1853          'Google Desktop'            => array('Google Desktop', ''),
1854          'Google Feedfetcher'        => array('Feedfetcher-Google', ''),
1855          'Google [Bot]'                => array('Googlebot', ''),
1856          'Heise IT-Markt [Crawler]'    => array('heise-IT-Markt-Crawler', ''),
1857          'Heritrix [Crawler]'        => array('heritrix/1.', ''),
1858          'IBM Research [Bot]'        => array('ibm.com/cs/crawler', ''),
1859          'ICCrawler - ICjobs'        => array('ICCrawler - ICjobs', ''),
1860          'ichiro [Crawler]'            => array('ichiro/', ''),
1861          'Majestic-12 [Bot]'            => array('MJ12bot/', ''),
1862          'Metager [Bot]'                => array('MetagerBot/', ''),
1863          'MSN NewsBlogs'                => array('msnbot-NewsBlogs/', ''),
1864          'MSN [Bot]'                    => array('msnbot/', ''),
1865          'MSNbot Media'                => array('msnbot-media/', ''),
1866          'NG-Search [Bot]'            => array('NG-Search/', ''),
1867          'Nutch [Bot]'                => array('http://lucene.apache.org/nutch/', ''),
1868          'Nutch/CVS [Bot]'            => array('NutchCVS/', ''),
1869          'OmniExplorer [Bot]'        => array('OmniExplorer_Bot/', ''),
1870          'Online link [Validator]'    => array('online link validator', ''),
1871          'psbot [Picsearch]'            => array('psbot/0', ''),
1872          'Seekport [Bot]'            => array('Seekbot/', ''),
1873          'Semrush [Bot]'                => array('SemrushBot/', ''),
1874          'Sensis [Crawler]'            => array('Sensis Web Crawler', ''),
1875          'SEO Crawler'                => array('SEO search Crawler/', ''),
1876          'Seoma [Crawler]'            => array('Seoma [SEO Crawler]', ''),
1877          'SEOSearch [Crawler]'        => array('SEOsearch/', ''),
1878          'Snappy [Bot]'                => array('Snappy/1.1 ( http://www.urltrends.com/ )', ''),
1879          'Steeler [Crawler]'            => array('http://www.tkl.iis.u-tokyo.ac.jp/~crawler/', ''),
1880          'Synoo [Bot]'                => array('SynooBot/', ''),
1881          'Telekom [Bot]'                => array('crawleradmin.t-info@telekom.de', ''),
1882          'TurnitinBot [Bot]'            => array('TurnitinBot/', ''),
1883          'Voyager [Bot]'                => array('voyager/', ''),
1884          'W3 [Sitesearch]'            => array('W3 SiteSearch Crawler', ''),
1885          'W3C [Linkcheck]'            => array('W3C-checklink/', ''),
1886          'W3C [Validator]'            => array('W3C_*Validator', ''),
1887          'WiseNut [Bot]'                => array('http://www.WISEnutbot.com', ''),
1888          'YaCy [Bot]'                => array('yacybot', ''),
1889          'Yahoo MMCrawler [Bot]'        => array('Yahoo-MMCrawler/', ''),
1890          'Yahoo Slurp [Bot]'            => array('Yahoo! DE Slurp', ''),
1891          'Yahoo [Bot]'                => array('Yahoo! Slurp', ''),
1892          'YahooSeeker [Bot]'            => array('YahooSeeker/', ''),
1893      );
1894  
1895      if (!function_exists('user_add'))
1896      {
1897          include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
1898      }
1899  
1900      foreach ($bots as $bot_name => $bot_ary)
1901      {
1902          $user_row = array(
1903              'user_type'                => USER_IGNORE,
1904              'group_id'                => $group_id,
1905              'username'                => $bot_name,
1906              'user_regdate'            => time(),
1907              'user_password'            => '',
1908              'user_colour'            => '9E8DA7',
1909              'user_email'            => '',
1910              'user_lang'                => $config['default_lang'],
1911              'user_style'            => 1,
1912              'user_timezone'            => 'UTC',
1913              'user_allow_massemail'    => 0,
1914          );
1915  
1916          $user_id = user_add($user_row);
1917  
1918          if ($user_id)
1919          {
1920              $sql = 'INSERT INTO ' . BOTS_TABLE . ' ' . $db->sql_build_array('INSERT', array(
1921                  'bot_active'    => 1,
1922                  'bot_name'        => $bot_name,
1923                  'user_id'        => $user_id,
1924                  'bot_agent'        => $bot_ary[0],
1925                  'bot_ip'        => $bot_ary[1])
1926              );
1927              $db->sql_query($sql);
1928          }
1929      }
1930  }
1931  
1932  /**
1933  * Update any dynamic configuration variables after the conversion is finished
1934  * @todo Confirm that this updates all relevant values since it has not necessarily been kept in sync with all changes
1935  */
1936  function update_dynamic_config()
1937  {
1938      global $db, $config;
1939  
1940      // Get latest username
1941      $sql = 'SELECT user_id, username, user_colour
1942          FROM ' . USERS_TABLE . '
1943          WHERE user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')';
1944  
1945      if (!empty($config['increment_user_id']))
1946      {
1947          $sql .= ' AND user_id <> ' . $config['increment_user_id'];
1948      }
1949  
1950      $sql .= ' ORDER BY user_id DESC';
1951  
1952      $result = $db->sql_query_limit($sql, 1);
1953      $row = $db->sql_fetchrow($result);
1954      $db->sql_freeresult($result);
1955  
1956      if ($row)
1957      {
1958          $config->set('newest_user_id', $row['user_id'], false);
1959          $config->set('newest_username', $row['username'], false);
1960          $config->set('newest_user_colour', $row['user_colour'], false);
1961      }
1962  
1963  //    Also do not reset record online user/date. There will be old data or the fresh data from the schema.
1964  //    set_config('record_online_users', 1, true);
1965  //    set_config('record_online_date', time(), true);
1966  
1967      $sql = 'SELECT COUNT(post_id) AS stat
1968          FROM ' . POSTS_TABLE . '
1969          WHERE post_visibility = ' . ITEM_APPROVED;
1970      $result = $db->sql_query($sql);
1971      $row = $db->sql_fetchrow($result);
1972      $db->sql_freeresult($result);
1973  
1974      $config->set('num_posts', (int) $row['stat'], false);
1975  
1976      $sql = 'SELECT COUNT(topic_id) AS stat
1977          FROM ' . TOPICS_TABLE . '
1978          WHERE topic_visibility = ' . ITEM_APPROVED;
1979      $result = $db->sql_query($sql);
1980      $row = $db->sql_fetchrow($result);
1981      $db->sql_freeresult($result);
1982  
1983      $config->set('num_topics', (int) $row['stat'], false);
1984  
1985      $sql = 'SELECT COUNT(user_id) AS stat
1986          FROM ' . USERS_TABLE . '
1987          WHERE user_type IN (' . USER_NORMAL . ',' . USER_FOUNDER . ')';
1988      $result = $db->sql_query($sql);
1989      $row = $db->sql_fetchrow($result);
1990      $db->sql_freeresult($result);
1991  
1992      $config->set('num_users', (int) $row['stat'], false);
1993  
1994      $sql = 'SELECT COUNT(attach_id) as stat
1995          FROM ' . ATTACHMENTS_TABLE . '
1996          WHERE is_orphan = 0';
1997      $result = $db->sql_query($sql);
1998      $config->set('num_files', (int) $db->sql_fetchfield('stat'), false);
1999      $db->sql_freeresult($result);
2000  
2001      $sql = 'SELECT SUM(filesize) as stat
2002          FROM ' . ATTACHMENTS_TABLE . '
2003          WHERE is_orphan = 0';
2004      $result = $db->sql_query($sql);
2005      $config->set('upload_dir_size', (float) $db->sql_fetchfield('stat'), false);
2006      $db->sql_freeresult($result);
2007  
2008      /**
2009      * We do not resync users post counts - this can be done by the admin after conversion if wanted.
2010      $sql = 'SELECT COUNT(post_id) AS num_posts, poster_id
2011          FROM ' . POSTS_TABLE . '
2012          WHERE post_postcount = 1
2013          GROUP BY poster_id';
2014      $result = $db->sql_query($sql);
2015  
2016      while ($row = $db->sql_fetchrow($result))
2017      {
2018          $db->sql_query('UPDATE ' . USERS_TABLE . " SET user_posts = {$row['num_posts']} WHERE user_id = {$row['poster_id']}");
2019      }
2020      $db->sql_freeresult($result);
2021      */
2022  }
2023  
2024  /**
2025  * Updates topics_posted entries
2026  */
2027  function update_topics_posted()
2028  {
2029      global $db;
2030  
2031      switch ($db->get_sql_layer())
2032      {
2033          case 'sqlite3':
2034              $db->sql_query('DELETE FROM ' . TOPICS_POSTED_TABLE);
2035          break;
2036  
2037          default:
2038              $db->sql_query('TRUNCATE TABLE ' . TOPICS_POSTED_TABLE);
2039          break;
2040      }
2041  
2042      // This can get really nasty... therefore we only do the last six months
2043      $get_from_time = time() - (6 * 4 * 7 * 24 * 60 * 60);
2044  
2045      // Select forum ids, do not include categories
2046      $sql = 'SELECT forum_id
2047          FROM ' . FORUMS_TABLE . '
2048          WHERE forum_type <> ' . FORUM_CAT;
2049      $result = $db->sql_query($sql);
2050  
2051      $forum_ids = array();
2052      while ($row = $db->sql_fetchrow($result))
2053      {
2054          $forum_ids[] = $row['forum_id'];
2055      }
2056      $db->sql_freeresult($result);
2057  
2058      // Any global announcements? ;)
2059      $forum_ids[] = 0;
2060  
2061      // Now go through the forums and get us some topics...
2062      foreach ($forum_ids as $forum_id)
2063      {
2064          $sql = 'SELECT p.poster_id, p.topic_id
2065              FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t
2066              WHERE t.forum_id = ' . $forum_id . '
2067                  AND t.topic_moved_id = 0
2068                  AND t.topic_last_post_time > ' . $get_from_time . '
2069                  AND t.topic_id = p.topic_id
2070                  AND p.poster_id <> ' . ANONYMOUS . '
2071              GROUP BY p.poster_id, p.topic_id';
2072          $result = $db->sql_query($sql);
2073  
2074          $posted = array();
2075          while ($row = $db->sql_fetchrow($result))
2076          {
2077              $posted[$row['poster_id']][] = $row['topic_id'];
2078          }
2079          $db->sql_freeresult($result);
2080  
2081          $sql_ary = array();
2082          foreach ($posted as $user_id => $topic_row)
2083          {
2084              foreach ($topic_row as $topic_id)
2085              {
2086                  $sql_ary[] = array(
2087                      'user_id'        => (int) $user_id,
2088                      'topic_id'        => (int) $topic_id,
2089                      'topic_posted'    => 1,
2090                  );
2091              }
2092          }
2093          unset($posted);
2094  
2095          if (count($sql_ary))
2096          {
2097              $db->sql_multi_insert(TOPICS_POSTED_TABLE, $sql_ary);
2098          }
2099      }
2100  }
2101  
2102  /**
2103  * Ensure that all users have a default group specified and update related information such as their colour
2104  */
2105  function fix_empty_primary_groups()
2106  {
2107      global $db;
2108  
2109      // Set group ids for users not already having it
2110      $sql = 'UPDATE ' . USERS_TABLE . ' SET group_id = ' . get_group_id('registered') . '
2111          WHERE group_id = 0 AND user_type = ' . USER_INACTIVE;
2112      $db->sql_query($sql);
2113  
2114      $sql = 'UPDATE ' . USERS_TABLE . ' SET group_id = ' . get_group_id('registered') . '
2115          WHERE group_id = 0 AND user_type = ' . USER_NORMAL;
2116      $db->sql_query($sql);
2117  
2118      $db->sql_query('UPDATE ' . USERS_TABLE . ' SET group_id = ' . get_group_id('guests') . ' WHERE user_id = ' . ANONYMOUS);
2119  
2120      $sql = 'SELECT user_id FROM ' . USER_GROUP_TABLE . ' WHERE group_id = ' . get_group_id('administrators');
2121      $result = $db->sql_query($sql);
2122  
2123      $user_ids = array();
2124      while ($row = $db->sql_fetchrow($result))
2125      {
2126          $user_ids[] = $row['user_id'];
2127      }
2128      $db->sql_freeresult($result);
2129  
2130      if (count($user_ids))
2131      {
2132          $db->sql_query('UPDATE ' . USERS_TABLE . ' SET group_id = ' . get_group_id('administrators') . '
2133              WHERE group_id = 0 AND ' . $db->sql_in_set('user_id', $user_ids));
2134      }
2135  
2136      $sql = 'SELECT user_id FROM ' . USER_GROUP_TABLE . ' WHERE group_id = ' . get_group_id('global_moderators');
2137      $result = $db->sql_query($sql);
2138  
2139      $user_ids = array();
2140      while ($row = $db->sql_fetchrow($result))
2141      {
2142          $user_ids[] = $row['user_id'];
2143      }
2144      $db->sql_freeresult($result);
2145  
2146      if (count($user_ids))
2147      {
2148          $db->sql_query('UPDATE ' . USERS_TABLE . ' SET group_id = ' . get_group_id('global_moderators') . '
2149              WHERE group_id = 0 AND ' . $db->sql_in_set('user_id', $user_ids));
2150      }
2151  
2152      // Set user colour
2153      $sql = 'SELECT group_id, group_colour FROM ' . GROUPS_TABLE . "
2154          WHERE group_colour <> ''";
2155      $result = $db->sql_query($sql);
2156  
2157      while ($row = $db->sql_fetchrow($result))
2158      {
2159          $db->sql_query('UPDATE ' . USERS_TABLE . " SET user_colour = '{$row['group_colour']}' WHERE group_id = {$row['group_id']}");
2160      }
2161      $db->sql_freeresult($result);
2162  }
2163  
2164  /**
2165  * Cleanly remove invalid user entries after converting the users table...
2166  */
2167  function remove_invalid_users()
2168  {
2169      global $db, $phpEx, $phpbb_root_path;
2170  
2171      // username_clean is UNIQUE
2172      $sql = 'SELECT user_id
2173          FROM ' . USERS_TABLE . "
2174          WHERE username_clean = ''";
2175      $result = $db->sql_query($sql);
2176      $row = $db->sql_fetchrow($result);
2177      $db->sql_freeresult($result);
2178  
2179      if ($row)
2180      {
2181          if (!function_exists('user_delete'))
2182          {
2183              include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
2184          }
2185  
2186          user_delete('remove', $row['user_id']);
2187      }
2188  }
2189  
2190  function convert_bbcode($message, $convert_size = true, $extended_bbcodes = false)
2191  {
2192      static $orig, $repl, $origx, $replx, $str_from, $str_to;
2193  
2194      if (empty($orig))
2195      {
2196          $orig = $repl = array();
2197  
2198          $orig[] = '#\[(php|sql)\](.*?)\[/(php|sql)\]#is';
2199          $repl[] = '[code]\2[/code]';
2200  
2201          $orig[] = '#\[font=[^\]]+\](.*?)\[/font\]#is';
2202          $repl[] = '\1';
2203  
2204          $orig[] = '#\[align=[a-z]+\](.*?)\[/align\]#is';
2205          $repl[] = '\1';
2206  
2207          $orig[] = '#\[/list=.*?\]#is';
2208          $repl[] = '[/list]';
2209  
2210          $origx = array(
2211              '#\[glow[^\]]+\](.*?)\[/glow\]#is',
2212              '#\[shadow[^\]]+\](.*?)\[/shadow\]#is',
2213              '#\[flash[^\]]+\](.*?)\[/flash\]#is'
2214          );
2215  
2216          $replx = array(
2217              '\1',
2218              '\1',
2219              '[url=\1]Flash[/url]'
2220          );
2221  
2222          $str_from = array(
2223              '[ftp]',    '[/ftp]',
2224              '[ftp=',    '[/ftp]',
2225              '[pre]',    '[/pre]',
2226              '[table]',    '[/table]',
2227              '[td]',        '[/td]',
2228              '[tr]',        '[/tr]',
2229              '[s]',        '[/s]',
2230              '[left]',    '[/left]',
2231              '[right]',    '[/right]',
2232              '[center]',    '[/center]',
2233              '[sub]',    '[/sub]',
2234              '[sup]',    '[/sup]',
2235              '[tt]',        '[/tt]',
2236              '[move]',    '[/move]',
2237              '[hr]'
2238          );
2239  
2240          $str_to = array(
2241              '[url]',    '[/url]',
2242              '[url=',    '[/url]',
2243              '[code]',    '[/code]',
2244              "\n",        '',
2245              '',            '',
2246              "\n",        '',
2247              '',            '',
2248              '',            '',
2249              '',            '',
2250              '',            '',
2251              '',            '',
2252              '',            '',
2253              '',            '',
2254              '',            '',
2255              "\n\n"
2256          );
2257  
2258          for ($i = 0, $end = count($str_from); $i < $end; ++$i)
2259          {
2260              $origx[] = '#\\' . str_replace(']', '\\]', $str_from[$i]) . '#is';
2261              $replx[] = $str_to[$i];
2262          }
2263      }
2264  
2265      if (preg_match_all('#\[email=([^\]]+)\](.*?)\[/email\]#i', $message, $m))
2266      {
2267          for ($i = 0, $end = count($m[1]); $i < $end; ++$i)
2268          {
2269              if ($m[1][$i] == $m[2][$i])
2270              {
2271                  $message = str_replace($m[0][$i], '[email]' . $m[1][$i] . '[/email]', $message);
2272              }
2273              else
2274              {
2275                  $message = str_replace($m[0][$i], $m[2][$i] . ' ([email]' . $m[1][$i] . '[/email])', $message);
2276              }
2277          }
2278      }
2279  
2280      if ($convert_size && preg_match('#\[size=[0-9]+\].*?\[/size\]#i', $message))
2281      {
2282          $size = array(9, 9, 12, 15, 18, 24, 29, 29, 29, 29);
2283          $message = preg_replace('#\[size=([0-9]+)\](.*?)\[/size\]#i', '[size=\1]\2[/size]', $message);
2284          $message = preg_replace('#\[size=[0-9]{2,}\](.*?)\[/size\]#i', '[size=29]\1[/size]', $message);
2285  
2286          for ($i = count($size); $i;)
2287          {
2288              $i--;
2289              $message = str_replace('[size=' . $i . ']', '[size=' . $size[$i] . ']', $message);
2290          }
2291      }
2292  
2293      if ($extended_bbcodes)
2294      {
2295          $message = preg_replace($origx, $replx, $message);
2296      }
2297  
2298      $message = preg_replace($orig, $repl, $message);
2299      return $message;
2300  }
2301  
2302  
2303  function copy_file($src, $trg, $overwrite = false, $die_on_failure = true, $source_relative_path = true)
2304  {
2305      global $convert, $phpbb_root_path, $user, $phpbb_filesystem;
2306  
2307      /** @var \phpbb\filesystem\filesystem_interface $filesystem */
2308      $filesystem = $phpbb_filesystem;
2309  
2310      if (substr($trg, -1) == '/')
2311      {
2312          $trg .= utf8_basename($src);
2313      }
2314      $src_path = relative_base($src, $source_relative_path, __LINE__, __FILE__);
2315      $trg_path = $trg;
2316  
2317      if (!$overwrite && @file_exists($trg_path))
2318      {
2319          return true;
2320      }
2321  
2322      if (!@file_exists($src_path))
2323      {
2324          return;
2325      }
2326  
2327      $path = $phpbb_root_path;
2328      $parts = explode('/', $trg);
2329      unset($parts[count($parts) - 1]);
2330  
2331      for ($i = 0, $end = count($parts); $i < $end; ++$i)
2332      {
2333          $path .= $parts[$i] . '/';
2334  
2335          if (!is_dir($path))
2336          {
2337              @mkdir($path, 0777);
2338          }
2339      }
2340  
2341      if (!$filesystem->is_writable($path))
2342      {
2343          @chmod($path, 0777);
2344      }
2345  
2346      if (!@copy($src_path, $phpbb_root_path . $trg_path))
2347      {
2348          $convert->p_master->error(sprintf($user->lang['COULD_NOT_COPY'], $src_path, $phpbb_root_path . $trg_path), __LINE__, __FILE__, !$die_on_failure);
2349          return;
2350      }
2351  
2352      if ($perm = @fileperms($src_path))
2353      {
2354          @chmod($phpbb_root_path . $trg_path, $perm);
2355      }
2356  
2357      return true;
2358  }
2359  
2360  function copy_dir($src, $trg, $copy_subdirs = true, $overwrite = false, $die_on_failure = true, $source_relative_path = true)
2361  {
2362      global $convert, $phpbb_root_path, $config, $user, $phpbb_filesystem;
2363  
2364      /** @var \phpbb\filesystem\filesystem_interface $filesystem */
2365      $filesystem = $phpbb_filesystem;
2366  
2367      $dirlist = $filelist = $bad_dirs = array();
2368      $src = path($src, $source_relative_path);
2369      $trg = path($trg);
2370      $src_path = relative_base($src, $source_relative_path, __LINE__, __FILE__);
2371      $trg_path = $phpbb_root_path . $trg;
2372  
2373      if (!is_dir($trg_path))
2374      {
2375          @mkdir($trg_path, 0777);
2376          @chmod($trg_path, 0777);
2377      }
2378  
2379      if (!$filesystem->is_writable($trg_path))
2380      {
2381          $bad_dirs[] = path($config['script_path']) . $trg;
2382      }
2383  
2384      if ($handle = @opendir($src_path))
2385      {
2386          while ($entry = readdir($handle))
2387          {
2388              if ($entry[0] == '.' || $entry == 'CVS' || $entry == 'index.htm')
2389              {
2390                  continue;
2391              }
2392  
2393              if (is_dir($src_path . $entry))
2394              {
2395                  $dirlist[] = $entry;
2396              }
2397              else
2398              {
2399                  $filelist[] = $entry;
2400              }
2401          }
2402          closedir($handle);
2403      }
2404      else if ($dir = @dir($src_path))
2405      {
2406          while ($entry = $dir->read())
2407          {
2408              if ($entry[0] == '.' || $entry == 'CVS' || $entry == 'index.htm')
2409              {
2410                  continue;
2411              }
2412  
2413              if (is_dir($src_path . $entry))
2414              {
2415                  $dirlist[] = $entry;
2416              }
2417              else
2418              {
2419                  $filelist[] = $entry;
2420              }
2421          }
2422          $dir->close();
2423      }
2424      else
2425      {
2426          $convert->p_master->error(sprintf($user->lang['CONV_ERROR_COULD_NOT_READ'], relative_base($src, $source_relative_path)), __LINE__, __FILE__);
2427      }
2428  
2429      if ($copy_subdirs)
2430      {
2431          for ($i = 0, $end = count($dirlist); $i < $end; ++$i)
2432          {
2433              $dir = $dirlist[$i];
2434  
2435              if ($dir == 'CVS')
2436              {
2437                  continue;
2438              }
2439  
2440              if (!is_dir($trg_path . $dir))
2441              {
2442                  @mkdir($trg_path . $dir, 0777);
2443                  @chmod($trg_path . $dir, 0777);
2444              }
2445  
2446              if (!$filesystem->is_writable($trg_path . $dir))
2447              {
2448                  $bad_dirs[] = $trg . $dir;
2449                  $bad_dirs[] = $trg_path . $dir;
2450              }
2451  
2452              if (!count($bad_dirs))
2453              {
2454                  copy_dir($src . $dir, $trg . $dir, true, $overwrite, $die_on_failure, $source_relative_path);
2455              }
2456          }
2457      }
2458  
2459      if (count($bad_dirs))
2460      {
2461          $str = (count($bad_dirs) == 1) ? $user->lang['MAKE_FOLDER_WRITABLE'] : $user->lang['MAKE_FOLDERS_WRITABLE'];
2462          sort($bad_dirs);
2463          $convert->p_master->error(sprintf($str, implode('<br />', $bad_dirs)), __LINE__, __FILE__);
2464      }
2465  
2466      for ($i = 0, $end = count($filelist); $i < $end; ++$i)
2467      {
2468          copy_file($src . $filelist[$i], $trg . $filelist[$i], $overwrite, $die_on_failure, $source_relative_path);
2469      }
2470  }
2471  
2472  function relative_base($path, $is_relative = true, $line = false, $file = false)
2473  {
2474      global $convert, $user;
2475  
2476      if (!$is_relative)
2477      {
2478          return $path;
2479      }
2480  
2481      if (empty($convert->options['forum_path']) && $is_relative)
2482      {
2483          $line = $line ? $line : __LINE__;
2484          $file = $file ? $file : __FILE__;
2485  
2486          $convert->p_master->error($user->lang['CONV_ERROR_NO_FORUM_PATH'], $line, $file);
2487      }
2488  
2489      return $convert->options['forum_path'] . '/' . $path;
2490  }
2491  
2492  function get_smiley_display()
2493  {
2494      static $smiley_count = 0;
2495      $smiley_count++;
2496      return ($smiley_count < 50) ? 1 : 0;
2497  }
2498  
2499  
2500  function fill_dateformat($user_dateformat)
2501  {
2502      global $config;
2503  
2504      return ((empty($user_dateformat)) ? $config['default_dateformat'] : $user_dateformat);
2505  }


Generated: Thu Mar 24 21:31:15 2022 Cross-referenced by PHPXref 0.7.1