Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

functions_convert.php

Zuletzt modifiziert: 02.04.2025, 15:01 - Dateigröße: 61.38 KiB


0001  <?php
0002  /**
0003  *
0004  * This file is part of the phpBB Forum Software package.
0005  *
0006  * @copyright (c) phpBB Limited <https://www.phpbb.com>
0007  * @license GNU General Public License, version 2 (GPL-2.0)
0008  *
0009  * For full copyright and license information, please see
0010  * the docs/CREDITS.txt file.
0011  *
0012  */
0013   
0014  /**
0015  * @ignore
0016  */
0017  if (!defined('IN_PHPBB'))
0018  {
0019      exit;
0020  }
0021   
0022  /**
0023  * Default avatar width/height
0024  * @ignore
0025  */
0026  define('DEFAULT_AVATAR_X', 80);
0027  define('DEFAULT_AVATAR_Y', 80);
0028   
0029  // Global functions - all functions can be used by convertors
0030   
0031  // SIMPLE FUNCTIONS
0032   
0033  /**
0034  * Return the preceding value
0035  */
0036  function dec($var)
0037  {
0038      return --$var;
0039  }
0040   
0041  /**
0042  * Return the next value
0043  */
0044  function inc($var)
0045  {
0046      return ++$var;
0047  }
0048   
0049  /**
0050  * Return whether the value is positive
0051  */
0052  function is_positive($n)
0053  {
0054      return ($n > 0) ? 1 : 0;
0055  }
0056   
0057  /**
0058  * Boolean inverse of the value
0059  */
0060  function not($var)
0061  {
0062      return ($var) ? 0 : 1;
0063  }
0064   
0065  /**
0066  * Convert a textual value to it's equivalent boolean value
0067  *
0068  * @param string $str String to convert (converts yes, on, y, 1 and true to boolean true)
0069  * @return boolean The equivalent value
0070  */
0071  function str_to_bool($str)
0072  {
0073      $str = strtolower($str);
0074      return ($str == 'yes' || $str == 'on' || $str == 'y' || $str == 'true' || $str == '1') ? true : false;
0075  }
0076   
0077  /**
0078  * Function to mimic php's empty() function (it is the same)
0079  */
0080  function is_empty($mixed)
0081  {
0082      return empty($mixed);
0083  }
0084   
0085  /**
0086  * Convert the name of a user's primary group to the appropriate equivalent phpBB group id
0087  *
0088  * @param string $status The name of the group
0089  * @return int The group_id corresponding to the equivalent group
0090  */
0091  function str_to_primary_group($status)
0092  {
0093      switch (ucfirst(strtolower($status)))
0094      {
0095          case 'Administrator':
0096              return get_group_id('administrators');
0097          break;
0098   
0099          case 'Super moderator':
0100          case 'Global moderator':
0101          case 'Moderator':
0102              return get_group_id('global_moderators');
0103          break;
0104   
0105          case 'Guest':
0106          case 'Anonymous':
0107              return get_group_id('guests');
0108          break;
0109   
0110          default:
0111              return get_group_id('registered');
0112          break;
0113      }
0114  }
0115   
0116  /**
0117  * Convert a boolean into the appropriate phpBB constant indicating whether the item is locked
0118  */
0119  function is_item_locked($bool)
0120  {
0121      return ($bool) ? ITEM_LOCKED : ITEM_UNLOCKED;
0122  }
0123   
0124  /**
0125  * Convert a value from days to seconds
0126  */
0127  function days_to_seconds($days)
0128  {
0129      return ($days * 86400);
0130  }
0131   
0132  /**
0133  * Determine whether a user is anonymous and return the appropriate new user_id
0134  */
0135  function is_user_anonymous($user_id)
0136  {
0137      return ($user_id > ANONYMOUS) ? $user_id : ANONYMOUS;
0138  }
0139   
0140  /**
0141  * Generate a key value based on existing values
0142  *
0143  * @param int $pad Amount to add to the maximum value
0144  * @return int Key value
0145  */
0146  function auto_id($pad = 0)
0147  {
0148      global $auto_id, $convert_row;
0149   
0150      if (!empty($convert_row['max_id']))
0151      {
0152          return $convert_row['max_id'] + $pad;
0153      }
0154   
0155      return $auto_id + $pad;
0156  }
0157   
0158  /**
0159  * Convert a boolean into the appropriate phpBB constant indicating whether the user is active
0160  */
0161  function set_user_type($user_active)
0162  {
0163      return ($user_active) ? USER_NORMAL : USER_INACTIVE;
0164  }
0165   
0166  /**
0167  * Convert a value from minutes to hours
0168  */
0169  function minutes_to_hours($minutes)
0170  {
0171      return ($minutes / 3600);
0172  }
0173   
0174  /**
0175  * Return the group_id for a given group name
0176  */
0177  function get_group_id($group_name)
0178  {
0179      global $db, $group_mapping;
0180   
0181      if (empty($group_mapping))
0182      {
0183          $sql = 'SELECT group_name, group_id
0184              FROM ' . GROUPS_TABLE;
0185          $result = $db->sql_query($sql);
0186   
0187          $group_mapping = array();
0188          while ($row = $db->sql_fetchrow($result))
0189          {
0190              $group_mapping[strtoupper($row['group_name'])] = (int) $row['group_id'];
0191          }
0192          $db->sql_freeresult($result);
0193      }
0194   
0195      if (!count($group_mapping))
0196      {
0197          add_default_groups();
0198          return get_group_id($group_name);
0199      }
0200   
0201      if (isset($group_mapping[strtoupper($group_name)]))
0202      {
0203          return $group_mapping[strtoupper($group_name)];
0204      }
0205   
0206      return $group_mapping['REGISTERED'];
0207  }
0208   
0209  /**
0210  * Convert a boolean into the appropriate phpBB constant indicating whether the topic is locked
0211  */
0212  function is_topic_locked($bool)
0213  {
0214      return (!empty($bool)) ? ITEM_LOCKED : ITEM_UNLOCKED;
0215  }
0216   
0217  /**
0218  * Generate a bbcode_uid value
0219  */
0220  function make_uid($timestamp)
0221  {
0222      static $last_timestamp, $last_uid;
0223   
0224      if (empty($last_timestamp) || $timestamp != $last_timestamp)
0225      {
0226          $last_uid = substr(base_convert(unique_id(), 16, 36), 0, BBCODE_UID_LEN);
0227      }
0228      $last_timestamp = $timestamp;
0229      return $last_uid;
0230  }
0231   
0232   
0233  /**
0234  * Validate a website address
0235  */
0236  function validate_website($url)
0237  {
0238      if ($url === 'http://')
0239      {
0240          return '';
0241      }
0242      else if (!preg_match('#^http[s]?://#i', $url) && strlen($url) > 0)
0243      {
0244          return 'http://' . $url;
0245      }
0246      return $url;
0247  }
0248   
0249  /**
0250  * Convert nulls to zeros for fields which allowed a NULL value in the source but not the destination
0251  */
0252  function null_to_zero($value)
0253  {
0254      return ($value === NULL) ? 0 : $value;
0255  }
0256   
0257  /**
0258  * Convert nulls to empty strings for fields which allowed a NULL value in the source but not the destination
0259  */
0260  function null_to_str($value)
0261  {
0262      return ($value === NULL) ? '' : $value;
0263  }
0264   
0265  // EXTENDED FUNCTIONS
0266   
0267  /**
0268  * Get old config value
0269  */
0270  function get_config_value($config_name)
0271  {
0272      static $convert_config;
0273   
0274      if (!isset($convert_config))
0275      {
0276          $convert_config = get_config();
0277      }
0278   
0279      if (!isset($convert_config[$config_name]))
0280      {
0281          return false;
0282      }
0283   
0284      return (empty($convert_config[$config_name])) ? '' : $convert_config[$config_name];
0285  }
0286   
0287  /**
0288  * Convert an IP address from the hexadecimal notation to normal dotted-quad notation
0289  */
0290  function decode_ip($int_ip)
0291  {
0292      if (!$int_ip)
0293      {
0294          return $int_ip;
0295      }
0296   
0297      $hexipbang = explode('.', chunk_split($int_ip, 2, '.'));
0298   
0299      // 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...
0300      if (count($hexipbang) < 4)
0301      {
0302          return $int_ip;
0303      }
0304   
0305      return hexdec($hexipbang[0]) . '.' . hexdec($hexipbang[1]) . '.' . hexdec($hexipbang[2]) . '.' . hexdec($hexipbang[3]);
0306  }
0307   
0308  /**
0309  * Reverse the encoding of wild-carded bans
0310  */
0311  function decode_ban_ip($int_ip)
0312  {
0313      return str_replace('255', '*', decode_ip($int_ip));
0314  }
0315   
0316  /**
0317  * Determine the MIME-type of a specified filename
0318  * This does not actually inspect the file, but simply uses the file extension
0319  */
0320  function mimetype($filename)
0321  {
0322      if (!preg_match('/\.([a-z0-9]+)$/i', $filename, $m))
0323      {
0324          return 'application/octet-stream';
0325      }
0326   
0327      switch (strtolower($m[1]))
0328      {
0329          case 'zip':        return 'application/zip';
0330          case 'jpeg':    return 'image/jpeg';
0331          case 'jpg':        return 'image/jpeg';
0332          case 'jpe':        return 'image/jpeg';
0333          case 'png':        return 'image/png';
0334          case 'gif':        return 'image/gif';
0335          case 'htm':
0336          case 'html':    return 'text/html';
0337          case 'tif':        return 'image/tiff';
0338          case 'tiff':    return 'image/tiff';
0339          case 'ras':        return 'image/x-cmu-raster';
0340          case 'pnm':        return 'image/x-portable-anymap';
0341          case 'pbm':        return 'image/x-portable-bitmap';
0342          case 'pgm':        return 'image/x-portable-graymap';
0343          case 'ppm':        return 'image/x-portable-pixmap';
0344          case 'rgb':        return 'image/x-rgb';
0345          case 'xbm':        return 'image/x-xbitmap';
0346          case 'xpm':        return 'image/x-xpixmap';
0347          case 'xwd':        return 'image/x-xwindowdump';
0348          case 'z':        return 'application/x-compress';
0349          case 'gtar':    return 'application/x-gtar';
0350          case 'tgz':        return 'application/x-gtar';
0351          case 'gz':        return 'application/x-gzip';
0352          case 'tar':        return 'application/x-tar';
0353          case 'xls':        return 'application/excel';
0354          case 'pdf':        return 'application/pdf';
0355          case 'ppt':        return 'application/powerpoint';
0356          case 'rm':        return 'application/vnd.rn-realmedia';
0357          case 'wma':        return 'audio/x-ms-wma';
0358          case 'swf':        return 'application/x-shockwave-flash';
0359          case 'ief':        return 'image/ief';
0360          case 'doc':
0361          case 'dot':
0362          case 'wrd':        return 'application/msword';
0363          case 'ai':
0364          case 'eps':
0365          case 'ps':        return 'application/postscript';
0366          case 'asc':
0367          case 'txt':
0368          case 'c':
0369          case 'cc':
0370          case 'h':
0371          case 'hh':
0372          case 'cpp':
0373          case 'hpp':
0374          case 'php':
0375          case 'php3':    return 'text/plain';
0376          default:         return 'application/octet-stream';
0377      }
0378  }
0379   
0380  /**
0381  * Obtain the dimensions of all remotely hosted avatars
0382  * This should only be called from execute_last
0383  * There can be significant network overhead if there are a large number of remote avatars
0384  * @todo Look at the option of allowing the user to decide whether this is called or to force the dimensions
0385  */
0386  function remote_avatar_dims()
0387  {
0388      global $db;
0389   
0390      $sql = 'SELECT user_id, user_avatar
0391          FROM ' . USERS_TABLE . '
0392          WHERE user_avatar_type = ' . AVATAR_REMOTE;
0393      $result = $db->sql_query($sql);
0394   
0395      $remote_avatars = array();
0396      while ($row = $db->sql_fetchrow($result))
0397      {
0398          $remote_avatars[(int) $row['user_id']] = $row['user_avatar'];
0399      }
0400      $db->sql_freeresult($result);
0401   
0402      foreach ($remote_avatars as $user_id => $avatar)
0403      {
0404          $width = (int) get_remote_avatar_dim($avatar, 0);
0405          $height = (int) get_remote_avatar_dim($avatar, 1);
0406   
0407          $sql = 'UPDATE ' . USERS_TABLE . '
0408              SET user_avatar_width = ' . (int) $width . ', user_avatar_height = ' . (int) $height . '
0409              WHERE user_id = ' . $user_id;
0410          $db->sql_query($sql);
0411      }
0412  }
0413   
0414  function import_avatar_gallery($gallery_name = '', $subdirs_as_galleries = false)
0415  {
0416      global $config, $convert, $user;
0417   
0418      $relative_path = empty($convert->convertor['source_path_absolute']);
0419   
0420      // check for trailing slash
0421      if (rtrim($convert->convertor['avatar_gallery_path'], '/') === '')
0422      {
0423          $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_GALLERY_PATH'], 'import_avatar_gallery()'), __LINE__, __FILE__);
0424      }
0425   
0426      $src_path = relative_base(path($convert->convertor['avatar_gallery_path'], $relative_path), $relative_path);
0427   
0428      if (is_dir($src_path))
0429      {
0430          // Do not die on failure... safe mode restrictions may be in effect.
0431          copy_dir($convert->convertor['avatar_gallery_path'], path($config['avatar_gallery_path']) . $gallery_name, !$subdirs_as_galleries, false, false, $relative_path);
0432   
0433          // only doing 1 level deep. (ibf 1.x)
0434          // notes: ibf has 2 tiers: directly in the avatar directory for base gallery (handled in the above statement), plus subdirs(handled below).
0435          // 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.
0436          if ($subdirs_as_galleries)
0437          {
0438              $dirlist = array();
0439              if ($handle = @opendir($src_path))
0440              {
0441                  while ($entry = readdir($handle))
0442                  {
0443                      if ($entry[0] == '.' || $entry == 'CVS' || $entry == 'index.htm')
0444                      {
0445                          continue;
0446                      }
0447   
0448                      if (is_dir($src_path . $entry))
0449                      {
0450                          $dirlist[] = $entry;
0451                      }
0452                  }
0453                  closedir($handle);
0454              }
0455              else if ($dir = @dir($src_path))
0456              {
0457                  while ($entry = $dir->read())
0458                  {
0459                      if ($entry[0] == '.' || $entry == 'CVS' || $entry == 'index.htm')
0460                      {
0461                          continue;
0462                      }
0463   
0464                      if (is_dir($src_path . $entry))
0465                      {
0466                          $dirlist[] = $entry;
0467                      }
0468                  }
0469                  $dir->close();
0470              }
0471   
0472              for ($i = 0, $end = count($dirlist); $i < $end; ++$i)
0473              {
0474                  $dir = $dirlist[$i];
0475   
0476                  // Do not die on failure... safe mode restrictions may be in effect.
0477                  copy_dir(path($convert->convertor['avatar_gallery_path'], $relative_path) . $dir, path($config['avatar_gallery_path']) . $dir, true, false, false, $relative_path);
0478              }
0479          }
0480      }
0481  }
0482   
0483  function import_attachment_files($category_name = '')
0484  {
0485      global $config, $convert, $db, $user;
0486   
0487      $sql = 'SELECT config_value AS upload_path
0488          FROM ' . CONFIG_TABLE . "
0489          WHERE config_name = 'upload_path'";
0490      $result = $db->sql_query($sql);
0491      $config['upload_path'] = $db->sql_fetchfield('upload_path');
0492      $db->sql_freeresult($result);
0493   
0494      $relative_path = empty($convert->convertor['source_path_absolute']);
0495   
0496      if (empty($convert->convertor['upload_path']))
0497      {
0498          $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_UPLOAD_DIR'], 'import_attachment_files()'), __LINE__, __FILE__);
0499      }
0500   
0501      if (is_dir(relative_base(path($convert->convertor['upload_path'], $relative_path), $relative_path)))
0502      {
0503          copy_dir($convert->convertor['upload_path'], path($config['upload_path']) . $category_name, true, false, true, $relative_path);
0504      }
0505  }
0506   
0507  function attachment_forum_perms($forum_id)
0508  {
0509      if (!is_array($forum_id))
0510      {
0511          $forum_id = array($forum_id);
0512      }
0513   
0514      return serialize($forum_id);
0515  }
0516   
0517  // base64todec function
0518  // -> from php manual?
0519  function base64_unpack($string)
0520  {
0521      $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-';
0522      $base = strlen($chars);
0523   
0524      $length = strlen($string);
0525      $number = 0;
0526   
0527      for ($i = 1; $i <= $length; $i++)
0528      {
0529          $pos = $length - $i;
0530          $operand = strpos($chars, substr($string, $pos, 1));
0531          $exponent = pow($base, $i-1);
0532          $dec_value = $operand * $exponent;
0533          $number += $dec_value;
0534      }
0535   
0536      return $number;
0537  }
0538   
0539  function _import_check($config_var, $source, $use_target)
0540  {
0541      global $convert, $config;
0542   
0543      $result = array(
0544          'orig_source'    => $source,
0545          'copied'        => false,
0546          'relative_path'    => (empty($convert->convertor['source_path_absolute'])) ? true : false,
0547      );
0548   
0549      // copy file will prepend $phpBB_root_path
0550      $target = $config[$config_var] . '/' . utf8_basename(($use_target === false) ? $source : $use_target);
0551   
0552      if (!empty($convert->convertor[$config_var]) && strpos($source, $convert->convertor[$config_var]) !== 0)
0553      {
0554          $source = $convert->convertor[$config_var] . $source;
0555      }
0556   
0557      $result['source'] = $source;
0558   
0559      if (file_exists(relative_base($source, $result['relative_path'], __LINE__, __FILE__)))
0560      {
0561          $result['copied'] = copy_file($source, $target, false, false, $result['relative_path']);
0562      }
0563   
0564      if ($result['copied'])
0565      {
0566          $result['target'] = utf8_basename($target);
0567      }
0568      else
0569      {
0570          $result['target'] = ($use_target !== false) ? $result['orig_source'] : utf8_basename($target);
0571      }
0572   
0573      return $result;
0574  }
0575   
0576  function import_attachment($source, $use_target = false)
0577  {
0578      if (empty($source))
0579      {
0580          return '';
0581      }
0582   
0583      global $convert, $config, $user;
0584   
0585      // check for trailing slash
0586      if (rtrim($convert->convertor['upload_path'], '/') === '')
0587      {
0588          $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_UPLOAD_DIR'], 'import_attachment()'), __LINE__, __FILE__);
0589      }
0590   
0591      $result = _import_check('upload_path', $source, $use_target);
0592   
0593      if ($result['copied'])
0594      {
0595          // Thumbnails?
0596          if (is_array($convert->convertor['thumbnails']))
0597          {
0598              $thumb_dir = $convert->convertor['thumbnails'][0];
0599              $thumb_prefix = $convert->convertor['thumbnails'][1];
0600              $thumb_source = $thumb_dir . $thumb_prefix . utf8_basename($result['source']);
0601   
0602              if (strpos($thumb_source, $convert->convertor['upload_path']) !== 0)
0603              {
0604                  $thumb_source = $convert->convertor['upload_path'] . $thumb_source;
0605              }
0606              $thumb_target = $config['upload_path'] . '/thumb_' . $result['target'];
0607   
0608              if (file_exists(relative_base($thumb_source, $result['relative_path'], __LINE__, __FILE__)))
0609              {
0610                  copy_file($thumb_source, $thumb_target, false, false, $result['relative_path']);
0611              }
0612          }
0613      }
0614   
0615      return $result['target'];
0616  }
0617   
0618  function import_rank($source, $use_target = false)
0619  {
0620      if (empty($source))
0621      {
0622          return '';
0623      }
0624   
0625      global $convert, $user;
0626   
0627      if (!isset($convert->convertor['ranks_path']))
0628      {
0629          $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_RANKS_PATH'], 'import_rank()'), __LINE__, __FILE__);
0630      }
0631   
0632      $result = _import_check('ranks_path', $source, $use_target);
0633      return $result['target'];
0634  }
0635   
0636  function import_smiley($source, $use_target = false)
0637  {
0638      if (empty($source))
0639      {
0640          return '';
0641      }
0642   
0643      global $convert, $user;
0644   
0645      // check for trailing slash
0646      if (rtrim($convert->convertor['smilies_path'], '/') === '')
0647      {
0648          $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_SMILIES_PATH'], 'import_smiley()'), __LINE__, __FILE__);
0649      }
0650   
0651      $result = _import_check('smilies_path', $source, $use_target);
0652      return $result['target'];
0653  }
0654   
0655  /*
0656  */
0657  function import_avatar($source, $use_target = false, $user_id = false)
0658  {
0659      if (empty($source) || preg_match('#^https?:#i', $source) || preg_match('#blank\.(gif|png)$#i', $source))
0660      {
0661          return;
0662      }
0663   
0664      global $convert, $config, $user;
0665   
0666      // check for trailing slash
0667      if (rtrim($convert->convertor['avatar_path'], '/') === '')
0668      {
0669          $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_AVATAR_PATH'], 'import_avatar()'), __LINE__, __FILE__);
0670      }
0671   
0672      if ($use_target === false && $user_id !== false)
0673      {
0674          $use_target = $config['avatar_salt'] . '_' . $user_id . '.' . substr(strrchr($source, '.'), 1);
0675      }
0676   
0677      _import_check('avatar_path', $source, $use_target);
0678   
0679      return ((!empty($user_id)) ? $user_id : $use_target) . '.' . substr(strrchr($source, '.'), 1);
0680  }
0681   
0682  /**
0683  * @todo all image dimension functions below (there are a *lot*) should get revisited and converted to one or two functions (no more needed, really).
0684  */
0685   
0686  /**
0687  * Calculate the size of the specified image
0688  * Called from the following functions for calculating the size of specific image types
0689  */
0690  function get_image_dim($source)
0691  {
0692      if (empty($source))
0693      {
0694          return array(0, 0);
0695      }
0696   
0697      global $convert;
0698   
0699      $relative_path = empty($convert->convertor['source_path_absolute']);
0700   
0701      if (file_exists(relative_base($source, $relative_path)))
0702      {
0703          $image = relative_base($source, $relative_path);
0704          return @getimagesize($image);
0705      }
0706   
0707      return false;
0708  }
0709   
0710  /**
0711  * Obtain the width of the specified smilie
0712  */
0713  function get_smiley_width($src)
0714  {
0715      return get_smiley_dim($src, 0);
0716  }
0717   
0718  /**
0719  * Obtain the height of the specified smilie
0720  */
0721  function get_smiley_height($src)
0722  {
0723      return get_smiley_dim($src, 1);
0724  }
0725   
0726  /**
0727  * Obtain the size of the specified smilie (using the cache if possible) and cache the value
0728  */
0729  function get_smiley_dim($source, $axis)
0730  {
0731      if (empty($source))
0732      {
0733          return 15;
0734      }
0735   
0736      static $smiley_cache = array();
0737   
0738      if (isset($smiley_cache[$source]))
0739      {
0740          return $smiley_cache[$source][$axis];
0741      }
0742   
0743      global $convert, $user;
0744   
0745      $orig_source = $source;
0746   
0747      if (!isset($convert->convertor['smilies_path']))
0748      {
0749          $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_SMILIES_PATH'], 'get_smiley_dim()'), __LINE__, __FILE__);
0750      }
0751   
0752      if (!empty($convert->convertor['smilies_path']) && strpos($source, $convert->convertor['smilies_path']) !== 0)
0753      {
0754          $source = $convert->convertor['smilies_path'] . $source;
0755      }
0756   
0757      $smiley_cache[$orig_source] = get_image_dim($source);
0758   
0759      if (empty($smiley_cache[$orig_source]) || empty($smiley_cache[$orig_source][0]) || empty($smiley_cache[$orig_source][1]))
0760      {
0761          $smiley_cache[$orig_source] = array(15, 15);
0762          return 15;
0763      }
0764   
0765      return $smiley_cache[$orig_source][$axis];
0766  }
0767   
0768  /**
0769  * Obtain the width of the specified avatar
0770  */
0771  function get_avatar_width($src, $func = false, $arg1 = false, $arg2 = false)
0772  {
0773      return get_avatar_dim($src, 0, $func, $arg1, $arg2);
0774  }
0775   
0776  /**
0777  * Obtain the height of the specified avatar
0778  */
0779  function get_avatar_height($src, $func = false, $arg1 = false, $arg2 = false)
0780  {
0781      return get_avatar_dim($src, 1, $func, $arg1, $arg2);
0782  }
0783   
0784  /**
0785  */
0786  function get_avatar_dim($src, $axis, $func = false, $arg1 = false, $arg2 = false)
0787  {
0788      $avatar_type = AVATAR_UPLOAD;
0789   
0790      if ($func)
0791      {
0792          if ($arg1 || $arg2)
0793          {
0794              $ary = array($arg1);
0795   
0796              if ($arg2)
0797              {
0798                  $ary[] = $arg2;
0799              }
0800   
0801              $avatar_type = call_user_func_array($func, $ary);
0802          }
0803          else
0804          {
0805              $avatar_type = call_user_func($func);
0806          }
0807      }
0808   
0809      switch ($avatar_type)
0810      {
0811          case AVATAR_UPLOAD:
0812              return get_upload_avatar_dim($src, $axis);
0813          break;
0814   
0815          case AVATAR_GALLERY:
0816              return get_gallery_avatar_dim($src, $axis);
0817          break;
0818   
0819          case AVATAR_REMOTE:
0820              // see notes on this functions usage and (hopefully) model $func to avoid this accordingly
0821              return get_remote_avatar_dim($src, $axis);
0822          break;
0823   
0824          default:
0825              $default_x = (defined('DEFAULT_AVATAR_X_CUSTOM')) ? DEFAULT_AVATAR_X_CUSTOM : DEFAULT_AVATAR_X;
0826              $default_y = (defined('DEFAULT_AVATAR_Y_CUSTOM')) ? DEFAULT_AVATAR_Y_CUSTOM : DEFAULT_AVATAR_Y;
0827   
0828              return $axis ? $default_y : $default_x;
0829          break;
0830      }
0831  }
0832   
0833  /**
0834  * Obtain the size of the specified uploaded avatar (using the cache if possible) and cache the value
0835  */
0836  function get_upload_avatar_dim($source, $axis)
0837  {
0838      static $cachedims = false;
0839      static $cachekey = false;
0840   
0841      if (empty($source))
0842      {
0843          return 0;
0844      }
0845   
0846      if ($cachekey == $source)
0847      {
0848          return $cachedims[$axis];
0849      }
0850   
0851      if (substr($source, 0, 7) == 'upload:')
0852      {
0853          $source = substr($source, 7);
0854      }
0855   
0856      global $convert, $user;
0857   
0858      if (!isset($convert->convertor['avatar_path']))
0859      {
0860          $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_AVATAR_PATH'], 'get_upload_avatar_dim()'), __LINE__, __FILE__);
0861      }
0862   
0863      if (!empty($convert->convertor['avatar_path']) && strpos($source, $convert->convertor['avatar_path']) !== 0)
0864      {
0865          $source = path($convert->convertor['avatar_path'], empty($convert->convertor['source_path_absolute'])) . $source;
0866      }
0867   
0868      $cachedims = get_image_dim($source);
0869   
0870      if (empty($cachedims) || empty($cachedims[0]) || empty($cachedims[1]))
0871      {
0872          $default_x = (defined('DEFAULT_AVATAR_X_CUSTOM')) ? DEFAULT_AVATAR_X_CUSTOM : DEFAULT_AVATAR_X;
0873          $default_y = (defined('DEFAULT_AVATAR_Y_CUSTOM')) ? DEFAULT_AVATAR_Y_CUSTOM : DEFAULT_AVATAR_Y;
0874   
0875          $cachedims = array($default_x, $default_y);
0876      }
0877   
0878      return $cachedims[$axis];
0879  }
0880   
0881  /**
0882  * Obtain the size of the specified gallery avatar (using the cache if possible) and cache the value
0883  */
0884  function get_gallery_avatar_dim($source, $axis)
0885  {
0886      if (empty($source))
0887      {
0888          return 0;
0889      }
0890   
0891      static $avatar_cache = array();
0892   
0893      if (isset($avatar_cache[$source]))
0894      {
0895          return $avatar_cache[$source][$axis];
0896      }
0897   
0898      global $convert, $user;
0899   
0900      $orig_source = $source;
0901   
0902      if (!isset($convert->convertor['avatar_gallery_path']))
0903      {
0904          $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_GALLERY_PATH'], 'get_gallery_avatar_dim()'), __LINE__, __FILE__);
0905      }
0906   
0907      if (!empty($convert->convertor['avatar_gallery_path']) && strpos($source, $convert->convertor['avatar_gallery_path']) !== 0)
0908      {
0909          $source = path($convert->convertor['avatar_gallery_path'], empty($convert->convertor['source_path_absolute'])) . $source;
0910      }
0911   
0912      $avatar_cache[$orig_source] = get_image_dim($source);
0913   
0914      if (empty($avatar_cache[$orig_source]) || empty($avatar_cache[$orig_source][0]) || empty($avatar_cache[$orig_source][1]))
0915      {
0916          $default_x = (defined('DEFAULT_AVATAR_X_CUSTOM')) ? DEFAULT_AVATAR_X_CUSTOM : DEFAULT_AVATAR_X;
0917          $default_y = (defined('DEFAULT_AVATAR_Y_CUSTOM')) ? DEFAULT_AVATAR_Y_CUSTOM : DEFAULT_AVATAR_Y;
0918   
0919          $avatar_cache[$orig_source] = array($default_x, $default_y);
0920      }
0921   
0922      return $avatar_cache[$orig_source][$axis];
0923  }
0924   
0925  /**
0926  * Obtain the size of the specified remote avatar (using the cache if possible) and cache the value
0927  * Whilst it's unlikely that remote avatars will be duplicated, it is possible so caching seems the best option
0928  * This should only be called from a post processing step due to the possibility of network timeouts
0929  */
0930  function get_remote_avatar_dim($src, $axis)
0931  {
0932      if (empty($src))
0933      {
0934          return 0;
0935      }
0936   
0937      static $remote_avatar_cache = array();
0938   
0939      // an ugly hack: we assume that the dimensions of each remote avatar are accessed exactly twice (x and y)
0940      if (isset($remote_avatar_cache[$src]))
0941      {
0942          $retval = $remote_avatar_cache[$src][$axis];
0943          unset($remote_avatar_cache);
0944          return $retval;
0945      }
0946   
0947      $url_info = @parse_url($src);
0948      if (empty($url_info['host']))
0949      {
0950          return 0;
0951      }
0952      $host = $url_info['host'];
0953      $port = (isset($url_info['port'])) ? $url_info['port'] : 0;
0954      $protocol = (isset($url_info['scheme'])) ? $url_info['scheme'] : 'http';
0955      if (empty($port))
0956      {
0957          switch (strtolower($protocol))
0958          {
0959              case 'ftp':
0960                  $port = 21;
0961                  break;
0962   
0963              case 'https':
0964                  $port = 443;
0965                  break;
0966   
0967              default:
0968                  $port = 80;
0969          }
0970      }
0971   
0972      $timeout = @ini_get('default_socket_timeout');
0973      @ini_set('default_socket_timeout', 2);
0974   
0975      // We're just trying to reach the server to avoid timeouts
0976      $fp = @fsockopen($host, $port, $errno, $errstr, 1);
0977      if ($fp)
0978      {
0979          $remote_avatar_cache[$src] = @getimagesize($src);
0980          fclose($fp);
0981      }
0982   
0983      $default_x     = (defined('DEFAULT_AVATAR_X_CUSTOM')) ? DEFAULT_AVATAR_X_CUSTOM : DEFAULT_AVATAR_X;
0984      $default_y     = (defined('DEFAULT_AVATAR_Y_CUSTOM')) ? DEFAULT_AVATAR_Y_CUSTOM : DEFAULT_AVATAR_Y;
0985      $default     = array($default_x, $default_y);
0986   
0987      if (empty($remote_avatar_cache[$src]) || empty($remote_avatar_cache[$src][0]) || empty($remote_avatar_cache[$src][1]))
0988      {
0989          $remote_avatar_cache[$src] = $default;
0990      }
0991      else
0992      {
0993          // We trust gallery and uploaded avatars to conform to the size settings; we might have to adjust here
0994          if ($remote_avatar_cache[$src][0] > $default_x || $remote_avatar_cache[$src][1] > $default_y)
0995          {
0996              $bigger = ($remote_avatar_cache[$src][0] > $remote_avatar_cache[$src][1]) ? 0 : 1;
0997              $ratio = $default[$bigger] / $remote_avatar_cache[$src][$bigger];
0998              $remote_avatar_cache[$src][0] = (int) ($remote_avatar_cache[$src][0] * $ratio);
0999              $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  }
2506