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