merge? merge.
[phpbb.git] / phpBB / includes / functions_convert.php
blob7a28cc2665f76af60c2d6a2411c71ff7af102cc2
1 <?php
2 /**
4 * @package install
5 * @version $Id$
6 * @copyright (c) 2006 phpBB Group
7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
9 */
11 /**
12 * @ignore
14 if (!defined('IN_PHPBB'))
16 exit;
19 /**
20 * Default avatar width/height
21 * @ignore
23 define('DEFAULT_AVATAR_X', 80);
24 define('DEFAULT_AVATAR_Y', 80);
26 // Global functions - all functions can be used by convertors
28 // SIMPLE FUNCTIONS
30 /**
31 * Return the preceding value
33 function dec($var)
35 return --$var;
38 /**
39 * Return the next value
41 function inc($var)
43 return ++$var;
46 /**
47 * Return whether the value is positive
49 function is_positive($n)
51 return ($n > 0) ? 1 : 0;
54 /**
55 * Boolean inverse of the value
57 function not($var)
59 return ($var) ? 0 : 1;
62 /**
63 * Convert a textual value to it's equivalent boolean value
65 * @param string $str String to convert (converts yes, on, y, 1 and true to boolean true)
66 * @return boolean The equivalent value
68 function str_to_bool($str)
70 $str = strtolower($str);
71 return ($str == 'yes' || $str == 'on' || $str == 'y' || $str == 'true' || $str == '1') ? true : false;
74 /**
75 * Function to mimic php's empty() function (it is the same)
77 function is_empty($mixed)
79 return empty($mixed);
82 /**
83 * Convert the name of a user's primary group to the appropriate equivalent phpBB group id
85 * @param string $status The name of the group
86 * @return int The group_id corresponding to the equivalent group
88 function str_to_primary_group($status)
90 switch (ucfirst(strtolower($status)))
92 case 'Administrator':
93 return get_group_id('administrators');
94 break;
96 case 'Super moderator':
97 case 'Global moderator':
98 case 'Moderator':
99 return get_group_id('global_moderators');
100 break;
102 case 'Guest':
103 case 'Anonymous':
104 return get_group_id('guests');
105 break;
107 default:
108 return get_group_id('registered');
109 break;
114 * Convert a boolean into the appropriate phpBB constant indicating whether the item is locked
116 function is_item_locked($bool)
118 return ($bool) ? ITEM_LOCKED : ITEM_UNLOCKED;
122 * Convert a value from days to seconds
124 function days_to_seconds($days)
126 return ($days * 86400);
130 * Determine whether a user is anonymous and return the appropriate new user_id
132 function is_user_anonymous($user_id)
134 return ($user_id > ANONYMOUS) ? $user_id : ANONYMOUS;
138 * Generate a key value based on existing values
140 * @param int $pad Amount to add to the maximum value
141 * @return int Key value
143 function auto_id($pad = 0)
145 global $auto_id, $convert_row;
147 if (!empty($convert_row['max_id']))
149 return $convert_row['max_id'] + $pad;
152 return $auto_id + $pad;
156 * Convert a boolean into the appropriate phpBB constant indicating whether the user is active
158 function set_user_type($user_active)
160 return ($user_active) ? USER_NORMAL : USER_INACTIVE;
164 * Convert a value from minutes to hours
166 function minutes_to_hours($minutes)
168 return ($minutes / 3600);
172 * Return the group_id for a given group name
174 function get_group_id($group_name)
176 global $db, $group_mapping;
178 if (empty($group_mapping))
180 $sql = 'SELECT group_name, group_id
181 FROM ' . GROUPS_TABLE;
182 $result = $db->sql_query($sql);
184 $group_mapping = array();
185 while ($row = $db->sql_fetchrow($result))
187 $group_mapping[strtoupper($row['group_name'])] = (int) $row['group_id'];
189 $db->sql_freeresult($result);
192 if (!sizeof($group_mapping))
194 add_default_groups();
195 return get_group_id($group_name);
198 if (isset($group_mapping[strtoupper($group_name)]))
200 return $group_mapping[strtoupper($group_name)];
203 return $group_mapping['REGISTERED'];
207 * Generate the email hash stored in the users table
209 function gen_email_hash($email)
211 return (crc32(strtolower($email)) . strlen($email));
215 * Convert a boolean into the appropriate phpBB constant indicating whether the topic is locked
217 function is_topic_locked($bool)
219 return (!empty($bool)) ? ITEM_LOCKED : ITEM_UNLOCKED;
223 * Generate a bbcode_uid value
225 function make_uid($timestamp)
227 static $last_timestamp, $last_uid;
229 if (empty($last_timestamp) || $timestamp != $last_timestamp)
231 $last_uid = substr(base_convert(unique_id(), 16, 36), 0, BBCODE_UID_LEN);
233 $last_timestamp = $timestamp;
234 return $last_uid;
239 * Validate a website address
241 function validate_website($url)
243 if ($url === 'http://')
245 return '';
247 else if (!preg_match('#^[a-z0-9]+://#i', $url) && strlen($url) > 0)
249 return 'http://' . $url;
251 return $url;
255 * Convert nulls to zeros for fields which allowed a NULL value in the source but not the destination
257 function null_to_zero($value)
259 return ($value === NULL) ? 0 : $value;
263 * Convert nulls to empty strings for fields which allowed a NULL value in the source but not the destination
265 function null_to_str($value)
267 return ($value === NULL) ? '' : $value;
270 // EXTENDED FUNCTIONS
273 * Get old config value
275 function get_config_value($config_name)
277 static $convert_config;
279 if (!isset($convert_config))
281 $convert_config = get_config();
284 if (!isset($convert_config[$config_name]))
286 return false;
289 return (empty($convert_config[$config_name])) ? '' : $convert_config[$config_name];
293 * Convert an IP address from the hexadecimal notation to normal dotted-quad notation
295 function decode_ip($int_ip)
297 if (!$int_ip)
299 return $int_ip;
302 $hexipbang = explode('.', chunk_split($int_ip, 2, '.'));
304 // 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...
305 if (sizeof($hexipbang) < 4)
307 return $int_ip;
310 return hexdec($hexipbang[0]) . '.' . hexdec($hexipbang[1]) . '.' . hexdec($hexipbang[2]) . '.' . hexdec($hexipbang[3]);
314 * Reverse the encoding of wild-carded bans
316 function decode_ban_ip($int_ip)
318 return str_replace('255', '*', decode_ip($int_ip));
322 * Determine the MIME-type of a specified filename
323 * This does not actually inspect the file, but simply uses the file extension
325 function mimetype($filename)
327 if (!preg_match('/\.([a-z0-9]+)$/i', $filename, $m))
329 return 'application/octet-stream';
332 switch (strtolower($m[1]))
334 case 'zip': return 'application/zip';
335 case 'jpeg': return 'image/jpeg';
336 case 'jpg': return 'image/jpeg';
337 case 'jpe': return 'image/jpeg';
338 case 'png': return 'image/png';
339 case 'gif': return 'image/gif';
340 case 'htm':
341 case 'html': return 'text/html';
342 case 'tif': return 'image/tiff';
343 case 'tiff': return 'image/tiff';
344 case 'ras': return 'image/x-cmu-raster';
345 case 'pnm': return 'image/x-portable-anymap';
346 case 'pbm': return 'image/x-portable-bitmap';
347 case 'pgm': return 'image/x-portable-graymap';
348 case 'ppm': return 'image/x-portable-pixmap';
349 case 'rgb': return 'image/x-rgb';
350 case 'xbm': return 'image/x-xbitmap';
351 case 'xpm': return 'image/x-xpixmap';
352 case 'xwd': return 'image/x-xwindowdump';
353 case 'z': return 'application/x-compress';
354 case 'gtar': return 'application/x-gtar';
355 case 'tgz': return 'application/x-gtar';
356 case 'gz': return 'application/x-gzip';
357 case 'tar': return 'application/x-tar';
358 case 'xls': return 'application/excel';
359 case 'pdf': return 'application/pdf';
360 case 'ppt': return 'application/powerpoint';
361 case 'rm': return 'application/vnd.rn-realmedia';
362 case 'wma': return 'audio/x-ms-wma';
363 case 'swf': return 'application/x-shockwave-flash';
364 case 'ief': return 'image/ief';
365 case 'doc':
366 case 'dot':
367 case 'wrd': return 'application/msword';
368 case 'ai':
369 case 'eps':
370 case 'ps': return 'application/postscript';
371 case 'asc':
372 case 'txt':
373 case 'c':
374 case 'cc':
375 case 'h':
376 case 'hh':
377 case 'cpp':
378 case 'hpp':
379 case 'php':
380 case 'php3': return 'text/plain';
381 default: return 'application/octet-stream';
386 * Obtain the dimensions of all remotely hosted avatars
387 * This should only be called from execute_last
388 * There can be significant network overhead if there are a large number of remote avatars
389 * @todo Look at the option of allowing the user to decide whether this is called or to force the dimensions
391 function remote_avatar_dims()
393 global $db;
395 $sql = 'SELECT user_id, user_avatar
396 FROM ' . USERS_TABLE . '
397 WHERE user_avatar_type = ' . AVATAR_REMOTE;
398 $result = $db->sql_query($sql);
400 $remote_avatars = array();
401 while ($row = $db->sql_fetchrow($result))
403 $remote_avatars[(int) $row['user_id']] = $row['user_avatar'];
405 $db->sql_freeresult($result);
407 foreach ($remote_avatars as $user_id => $avatar)
409 $width = (int) get_remote_avatar_dim($avatar, 0);
410 $height = (int) get_remote_avatar_dim($avatar, 1);
412 $sql = 'UPDATE ' . USERS_TABLE . '
413 SET user_avatar_width = ' . (int) $width . ', user_avatar_height = ' . (int) $height . '
414 WHERE user_id = ' . $user_id;
415 $db->sql_query($sql);
419 function import_avatar_gallery($gallery_name = '', $subdirs_as_galleries = false)
421 global $config, $convert, $user;
423 $relative_path = empty($convert->convertor['source_path_absolute']);
425 if (empty($convert->convertor['avatar_gallery_path']))
427 $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_GALLERY_PATH'], 'import_avatar_gallery()'), __LINE__, __FILE__);
430 $src_path = relative_base(path($convert->convertor['avatar_gallery_path'], $relative_path), $relative_path);
432 if (is_dir($src_path))
434 // Do not die on failure... safe mode restrictions may be in effect.
435 copy_dir($convert->convertor['avatar_gallery_path'], path($config['avatar_gallery_path']) . $gallery_name, !$subdirs_as_galleries, false, false, $relative_path);
437 // only doing 1 level deep. (ibf 1.x)
438 // notes: ibf has 2 tiers: directly in the avatar directory for base gallery (handled in the above statement), plus subdirs(handled below).
439 // 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.
440 if ($subdirs_as_galleries)
442 $dirlist = array();
443 if ($handle = @opendir($src_path))
445 while ($entry = readdir($handle))
447 if ($entry[0] == '.' || $entry == 'CVS' || $entry == 'index.htm')
449 continue;
452 if (is_dir($src_path . $entry))
454 $dirlist[] = $entry;
457 closedir($handle);
459 else if ($dir = @dir($src_path))
461 while ($entry = $dir->read())
463 if ($entry[0] == '.' || $entry == 'CVS' || $entry == 'index.htm')
465 continue;
468 if (is_dir($src_path . $entry))
470 $dirlist[] = $entry;
473 $dir->close();
476 for ($i = 0; $i < sizeof($dirlist); ++$i)
478 $dir = $dirlist[$i];
480 // Do not die on failure... safe mode restrictions may be in effect.
481 copy_dir(path($convert->convertor['avatar_gallery_path'], $relative_path) . $dir, path($config['avatar_gallery_path']) . $dir, true, false, false, $relative_path);
487 function import_attachment_files($category_name = '')
489 global $config, $convert, $db, $user;
491 $sql = 'SELECT config_value AS upload_path
492 FROM ' . CONFIG_TABLE . "
493 WHERE config_name = 'upload_path'";
494 $result = $db->sql_query($sql);
495 $config['upload_path'] = $db->sql_fetchfield('upload_path');
496 $db->sql_freeresult($result);
498 $relative_path = empty($convert->convertor['source_path_absolute']);
500 if (empty($convert->convertor['upload_path']))
502 $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_UPLOAD_DIR'], 'import_attachment_files()'), __LINE__, __FILE__);
505 if (is_dir(relative_base(path($convert->convertor['upload_path'], $relative_path), $relative_path)))
507 copy_dir($convert->convertor['upload_path'], path($config['upload_path']) . $category_name, true, false, true, $relative_path);
511 function attachment_forum_perms($forum_id)
513 if (!is_array($forum_id))
515 $forum_id = array($forum_id);
518 return serialize($forum_id);
521 // base64todec function
522 // -> from php manual?
523 function base64_unpack($string)
525 $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-';
526 $base = strlen($chars);
528 $length = strlen($string);
529 $number = 0;
531 for ($i = 1; $i <= $length; $i++)
533 $pos = $length - $i;
534 $operand = strpos($chars, substr($string, $pos, 1));
535 $exponent = pow($base, $i-1);
536 $dec_value = $operand * $exponent;
537 $number += $dec_value;
540 return $number;
543 function _import_check($config_var, $source, $use_target)
545 global $convert, $config;
547 $result = array(
548 'orig_source' => $source,
549 'copied' => false,
550 'relative_path' => (empty($convert->convertor['source_path_absolute'])) ? true : false,
553 // copy file will prepend PHPBB_ROOT_PATH
554 $target = $config[$config_var] . '/' . basename(($use_target === false) ? $source : $use_target);
556 if (!empty($convert->convertor[$config_var]) && strpos($source, $convert->convertor[$config_var]) !== 0)
558 $source = $convert->convertor[$config_var] . $source;
561 $result['source'] = $source;
563 if (file_exists(relative_base($source, $result['relative_path'], __LINE__, __FILE__)))
565 $result['copied'] = copy_file($source, $target, false, false, $result['relative_path']);
568 if ($result['copied'])
570 $result['target'] = basename($target);
572 else
574 $result['target'] = ($use_target !== false) ? $result['orig_source'] : basename($target);
577 return $result;
580 function import_attachment($source, $use_target = false)
582 if (empty($source))
584 return '';
587 global $convert, $config, $user;
589 if (empty($convert->convertor['upload_path']))
591 $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_UPLOAD_DIR'], 'import_attachment()'), __LINE__, __FILE__);
594 $result = _import_check('upload_path', $source, $use_target);
596 if ($result['copied'])
598 // Thumbnails?
599 if (is_array($convert->convertor['thumbnails']))
601 $thumb_dir = $convert->convertor['thumbnails'][0];
602 $thumb_prefix = $convert->convertor['thumbnails'][1];
603 $thumb_source = $thumb_dir . $thumb_prefix . basename($result['source']);
605 if (strpos($thumb_source, $convert->convertor['upload_path']) !== 0)
607 $thumb_source = $convert->convertor['upload_path'] . $thumb_source;
609 $thumb_target = $config['upload_path'] . '/thumb_' . $result['target'];
611 if (file_exists(relative_base($thumb_source, $result['relative_path'], __LINE__, __FILE__)))
613 copy_file($thumb_source, $thumb_target, false, false, $result['relative_path']);
618 return $result['target'];
621 function import_rank($source, $use_target = false)
623 if (empty($source))
625 return '';
628 global $convert, $config, $user;
630 if (!isset($convert->convertor['ranks_path']))
632 $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_RANKS_PATH'], 'import_rank()'), __LINE__, __FILE__);
635 $result = _import_check('ranks_path', $source, $use_target);
636 return $result['target'];
639 function import_smiley($source, $use_target = false)
641 if (empty($source))
643 return '';
646 global $convert, $config, $user;
648 if (!isset($convert->convertor['smilies_path']))
650 $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_SMILIES_PATH'], 'import_smiley()'), __LINE__, __FILE__);
653 $result = _import_check('smilies_path', $source, $use_target);
654 return $result['target'];
659 function import_avatar($source, $use_target = false, $user_id = false)
661 if (empty($source) || preg_match('#^https?:#i', $source) || preg_match('#blank\.(gif|png)$#i', $source))
663 return;
666 global $convert, $config, $user;
668 if (!isset($convert->convertor['avatar_path']))
670 $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_AVATAR_PATH'], 'import_avatar()'), __LINE__, __FILE__);
673 if ($use_target === false && $user_id !== false)
675 $use_target = $config['avatar_salt'] . '_' . $user_id . '.' . substr(strrchr($source, '.'), 1);
678 $result = _import_check('avatar_path', $source, $use_target);
680 return ((!empty($user_id)) ? $user_id : $use_target) . '.' . substr(strrchr($source, '.'), 1);
684 * @todo all image dimension functions below (there are a *lot*) should get revisited and converted to one or two functions (no more needed, really).
688 * Calculate the size of the specified image
689 * Called from the following functions for calculating the size of specific image types
691 function get_image_dim($source)
693 if (empty($source))
695 return array(0, 0);
698 global $convert;
700 $relative_path = empty($convert->convertor['source_path_absolute']);
702 if (file_exists(relative_base($source, $relative_path)))
704 $image = relative_base($source, $relative_path);
705 return @getimagesize($image);
708 return false;
712 * Obtain the width of the specified smilie
714 function get_smiley_width($src)
716 return get_smiley_dim($src, 0);
720 * Obtain the height of the specified smilie
722 function get_smiley_height($src)
724 return get_smiley_dim($src, 1);
728 * Obtain the size of the specified smilie (using the cache if possible) and cache the value
730 function get_smiley_dim($source, $axis)
732 if (empty($source))
734 return 15;
737 static $smiley_cache = array();
739 if (isset($smiley_cache[$source]))
741 return $smiley_cache[$source][$axis];
744 global $convert, $config, $user;
746 $orig_source = $source;
748 if (!isset($convert->convertor['smilies_path']))
750 $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_SMILIES_PATH'], 'get_smiley_dim()'), __LINE__, __FILE__);
753 if (!empty($convert->convertor['smilies_path']) && strpos($source, $convert->convertor['smilies_path']) !== 0)
755 $source = $convert->convertor['smilies_path'] . $source;
758 $smiley_cache[$orig_source] = get_image_dim($source);
760 if (empty($smiley_cache[$orig_source]) || empty($smiley_cache[$orig_source][0]) || empty($smiley_cache[$orig_source][1]))
762 $smiley_cache[$orig_source] = array(15, 15);
763 return 15;
766 return $smiley_cache[$orig_source][$axis];
770 * Obtain the width of the specified avatar
772 function get_avatar_width($src, $func = false, $arg1 = false, $arg2 = false)
774 return get_avatar_dim($src, 0, $func, $arg1, $arg2);
778 * Obtain the height of the specified avatar
780 function get_avatar_height($src, $func = false, $arg1 = false, $arg2 = false)
782 return get_avatar_dim($src, 1, $func, $arg1, $arg2);
787 function get_avatar_dim($src, $axis, $func = false, $arg1 = false, $arg2 = false)
789 $avatar_type = AVATAR_UPLOAD;
791 if ($func)
793 if ($arg1 || $arg2)
795 $ary = array($arg1);
797 if ($arg2)
799 $ary[] = $arg2;
802 $avatar_type = call_user_func_array($func, $ary);
804 else
806 $avatar_type = call_user_func($func);
810 switch ($avatar_type)
812 case AVATAR_UPLOAD:
813 return get_upload_avatar_dim($src, $axis);
814 break;
816 case AVATAR_GALLERY:
817 return get_gallery_avatar_dim($src, $axis);
818 break;
820 case AVATAR_REMOTE:
821 // see notes on this functions usage and (hopefully) model $func to avoid this accordingly
822 return get_remote_avatar_dim($src, $axis);
823 break;
825 default:
826 $default_x = (defined('DEFAULT_AVATAR_X_CUSTOM')) ? DEFAULT_AVATAR_X_CUSTOM : DEFAULT_AVATAR_X;
827 $default_y = (defined('DEFAULT_AVATAR_Y_CUSTOM')) ? DEFAULT_AVATAR_Y_CUSTOM : DEFAULT_AVATAR_Y;
829 return $axis ? $default_y : $default_x;
830 break;
835 * Obtain the size of the specified uploaded avatar (using the cache if possible) and cache the value
837 function get_upload_avatar_dim($source, $axis)
839 static $cachedims = false;
840 static $cachekey = false;
842 if (empty($source))
844 return 0;
847 if ($cachekey == $source)
849 return $cachedims[$axis];
852 $orig_source = $source;
854 if (substr($source, 0, 7) == 'upload:')
856 $source = substr($source, 7);
859 global $convert, $config, $user;
861 if (!isset($convert->convertor['avatar_path']))
863 $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_AVATAR_PATH'], 'get_upload_avatar_dim()'), __LINE__, __FILE__);
866 if (!empty($convert->convertor['avatar_path']) && strpos($source, $convert->convertor['avatar_path']) !== 0)
868 $source = path($convert->convertor['avatar_path'], empty($convert->convertor['source_path_absolute'])) . $source;
871 $cachedims = get_image_dim($source);
873 if (empty($cachedims) || empty($cachedims[0]) || empty($cachedims[1]))
875 $default_x = (defined('DEFAULT_AVATAR_X_CUSTOM')) ? DEFAULT_AVATAR_X_CUSTOM : DEFAULT_AVATAR_X;
876 $default_y = (defined('DEFAULT_AVATAR_Y_CUSTOM')) ? DEFAULT_AVATAR_Y_CUSTOM : DEFAULT_AVATAR_Y;
878 $cachedims = array($default_x, $default_y);
881 return $cachedims[$axis];
885 * Obtain the size of the specified gallery avatar (using the cache if possible) and cache the value
887 function get_gallery_avatar_dim($source, $axis)
889 if (empty($source))
891 return 0;
894 static $avatar_cache = array();
896 if (isset($avatar_cache[$source]))
898 return $avatar_cache[$source][$axis];
901 global $convert, $config, $user;
903 $orig_source = $source;
905 if (!isset($convert->convertor['avatar_gallery_path']))
907 $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_GALLERY_PATH'], 'get_gallery_avatar_dim()'), __LINE__, __FILE__);
910 if (!empty($convert->convertor['avatar_gallery_path']) && strpos($source, $convert->convertor['avatar_gallery_path']) !== 0)
912 $source = path($convert->convertor['avatar_gallery_path'], empty($convert->convertor['source_path_absolute'])) . $source;
915 $avatar_cache[$orig_source] = get_image_dim($source);
917 if (empty($avatar_cache[$orig_source]) || empty($avatar_cache[$orig_source][0]) || empty($avatar_cache[$orig_source][1]))
919 $default_x = (defined('DEFAULT_AVATAR_X_CUSTOM')) ? DEFAULT_AVATAR_X_CUSTOM : DEFAULT_AVATAR_X;
920 $default_y = (defined('DEFAULT_AVATAR_Y_CUSTOM')) ? DEFAULT_AVATAR_Y_CUSTOM : DEFAULT_AVATAR_Y;
922 $avatar_cache[$orig_source] = array($default_x, $default_y);
925 return $avatar_cache[$orig_source][$axis];
929 * Obtain the size of the specified remote avatar (using the cache if possible) and cache the value
930 * Whilst it's unlikely that remote avatars will be duplicated, it is possible so caching seems the best option
931 * This should only be called from a post processing step due to the possibility of network timeouts
933 function get_remote_avatar_dim($src, $axis)
935 if (empty($src))
937 return 0;
940 static $remote_avatar_cache = array();
942 // an ugly hack: we assume that the dimensions of each remote avatar are accessed exactly twice (x and y)
943 if (isset($remote_avatar_cache[$src]))
945 $retval = $remote_avatar_cache[$src][$axis];
946 unset($remote_avatar_cache);
947 return $retval;
950 $url_info = @parse_url($src);
951 if (empty($url_info['host']))
953 return 0;
955 $host = $url_info['host'];
956 $port = (isset($url_info['port'])) ? $url_info['port'] : 0;
957 $protocol = (isset($url_info['scheme'])) ? $url_info['scheme'] : 'http';
958 if (empty($port))
960 switch(strtolower($protocol))
962 case 'ftp':
963 $port = 21;
964 break;
966 case 'https':
967 $port = 443;
968 break;
970 default:
971 $port = 80;
975 $timeout = @ini_get('default_socket_timeout');
976 @ini_set('default_socket_timeout', 2);
978 // We're just trying to reach the server to avoid timeouts
979 $fp = @fsockopen($host, $port, $errno, $errstr, 1);
980 if ($fp)
982 $remote_avatar_cache[$src] = @getimagesize($src);
983 fclose($fp);
986 $default_x = (defined('DEFAULT_AVATAR_X_CUSTOM')) ? DEFAULT_AVATAR_X_CUSTOM : DEFAULT_AVATAR_X;
987 $default_y = (defined('DEFAULT_AVATAR_Y_CUSTOM')) ? DEFAULT_AVATAR_Y_CUSTOM : DEFAULT_AVATAR_Y;
988 $default = array($default_x, $default_y);
990 if (empty($remote_avatar_cache[$src]) || empty($remote_avatar_cache[$src][0]) || empty($remote_avatar_cache[$src][1]))
992 $remote_avatar_cache[$src] = $default;
994 else
996 // We trust gallery and uploaded avatars to conform to the size settings; we might have to adjust here
997 if ($remote_avatar_cache[$src][0] > $default_x || $remote_avatar_cache[$src][1] > $default_y)
999 $bigger = ($remote_avatar_cache[$src][0] > $remote_avatar_cache[$src][1]) ? 0 : 1;
1000 $ratio = $default[$bigger] / $remote_avatar_cache[$src][$bigger];
1001 $remote_avatar_cache[$src][0] = (int)($remote_avatar_cache[$src][0] * $ratio);
1002 $remote_avatar_cache[$src][1] = (int)($remote_avatar_cache[$src][1] * $ratio);
1006 @ini_set('default_socket_timeout', $timeout);
1007 return $remote_avatar_cache[$src][$axis];
1010 function set_user_options()
1012 global $convert_row;
1014 // Key need to be set in row, else default value is chosen
1015 $keyoptions = array(
1016 'viewimg' => array('bit' => 0, 'default' => 1),
1017 'viewflash' => array('bit' => 1, 'default' => 1),
1018 'viewsmilies' => array('bit' => 2, 'default' => 1),
1019 'viewsigs' => array('bit' => 3, 'default' => 1),
1020 'viewavatars' => array('bit' => 4, 'default' => 1),
1021 'viewcensors' => array('bit' => 5, 'default' => 1),
1022 'attachsig' => array('bit' => 6, 'default' => 0),
1023 'bbcode' => array('bit' => 8, 'default' => 1),
1024 'smilies' => array('bit' => 9, 'default' => 1),
1025 'popuppm' => array('bit' => 10, 'default' => 0),
1028 $option_field = 0;
1030 foreach ($keyoptions as $key => $key_ary)
1032 $value = (isset($convert_row[$key])) ? (int) $convert_row[$key] : $key_ary['default'];
1034 if ($value && !($option_field & 1 << $key_ary['bit']))
1036 $option_field += 1 << $key_ary['bit'];
1040 return $option_field;
1044 * Index messages on the fly as we convert them
1045 * @todo naderman, can you check that this works with the new search plugins as it's use is currently disabled (and thus untested)
1046 function search_indexing($message = '')
1048 global $fulltext_search, $convert_row;
1050 if (!isset($convert_row['post_id']))
1052 return;
1055 if (!$message)
1057 if (!isset($convert_row['message']))
1059 return;
1062 $message = $convert_row['message'];
1065 $title = (isset($convert_row['title'])) ? $convert_row['title'] : '';
1067 $fulltext_search->index('post', $convert_row['post_id'], $message, $title, $convert_row['poster_id'], $convert_row['forum_id']);
1071 function make_unique_filename($filename)
1073 if (!strlen($filename))
1075 $filename = md5(unique_id()) . '.dat';
1077 else if ($filename[0] == '.')
1079 $filename = md5(unique_id()) . $filename;
1081 else if (preg_match('/\.([a-z]+)$/i', $filename, $m))
1083 $filename = preg_replace('/\.([a-z]+)$/i', '_' . md5(unique_id()) . '.\1', $filename);
1085 else
1087 $filename .= '_' . md5(unique_id()) . '.dat';
1090 return $filename;
1093 function words_unique(&$words)
1095 reset($words);
1096 $return_array = array();
1098 $word = current($words);
1101 $return_array[$word] = $word;
1103 while ($word = next($words));
1105 return $return_array;
1109 * Adds a user to the specified group and optionally makes them a group leader
1110 * This function does not create the group if it does not exist and so should only be called after the groups have been created
1112 function add_user_group($group_id, $user_id, $group_leader=false)
1114 global $convert, $config, $user, $db;
1116 $sql = 'INSERT INTO ' . USER_GROUP_TABLE . ' ' . $db->sql_build_array('INSERT', array(
1117 'group_id' => $group_id,
1118 'user_id' => $user_id,
1119 'group_leader' => ($group_leader) ? 1 : 0,
1120 'user_pending' => 0));
1121 $db->sql_query($sql);
1124 // STANDALONE FUNCTIONS
1127 * Add users to the pre-defined "special" groups
1129 * @param string $group The name of the special group to add to
1130 * @param string $select_query An SQL query to retrieve the user(s) to add to the group
1132 function user_group_auth($group, $select_query, $use_src_db)
1134 global $convert, $config, $user, $db, $src_db, $same_db;
1136 if (!in_array($group, array('guests', 'registered', 'registered_coppa', 'global_moderators', 'administrators', 'bots')))
1138 $convert->p_master->error(sprintf($user->lang['CONV_ERROR_WRONG_GROUP'], $group, 'user_group_auth()'), __LINE__, __FILE__, true);
1139 return;
1142 $sql = 'SELECT group_id
1143 FROM ' . GROUPS_TABLE . "
1144 WHERE group_name_clean = '" . $db->sql_escape(utf8_clean_string($group)) . "'";
1145 $result = $db->sql_query($sql);
1146 $group_id = (int) $db->sql_fetchfield('group_id');
1147 $db->sql_freeresult($result);
1149 if (!$group_id)
1151 $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_GROUP'], $group, 'user_group_auth()'), __LINE__, __FILE__, true);
1152 return;
1155 if ($same_db || !$use_src_db)
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);
1161 else
1163 $result = $src_db->sql_query(str_replace('{' . strtoupper($group) . '}', $group_id . ' ', $select_query));
1164 while ($row = $src_db->sql_fetchrow($result))
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);
1171 $src_db->sql_freeresult($result);
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)
1180 function get_config()
1182 static $convert_config;
1183 global $user;
1185 if (isset($convert_config))
1187 return $convert_config;
1190 global $src_db, $same_db, $config;
1191 global $convert;
1193 if ($convert->config_schema['table_format'] != 'file')
1195 if ($convert->mysql_convert && $same_db)
1197 $src_db->sql_query("SET NAMES 'binary'");
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);
1204 if (!$row)
1206 $convert->p_master->error($user->lang['CONV_ERROR_GET_CONFIG'], __LINE__, __FILE__);
1210 if (is_array($convert->config_schema['table_format']))
1212 $convert_config = array();
1213 list($key, $val) = each($convert->config_schema['table_format']);
1217 $convert_config[$row[$key]] = $row[$val];
1219 while ($row = $src_db->sql_fetchrow($result));
1220 $src_db->sql_freeresult($result);
1222 if ($convert->mysql_convert && $same_db)
1224 $src_db->sql_query("SET NAMES 'utf8'");
1227 else if ($convert->config_schema['table_format'] == 'file')
1229 $filename = $convert->options['forum_path'] . '/' . $convert->config_schema['filename'];
1230 if (!file_exists($filename))
1232 $convert->p_master->error($user->lang['FILE_NOT_FOUND'] . ': ' . $filename, __LINE__, __FILE__);
1235 $convert_config = extract_variables_from_file($filename);
1236 if (!empty($convert->config_schema['array_name']))
1238 $convert_config = $convert_config[$convert->config_schema['array_name']];
1241 else
1243 $convert_config = $row;
1244 if ($convert->mysql_convert && $same_db)
1246 $src_db->sql_query("SET NAMES 'utf8'");
1250 if (!sizeof($convert_config))
1252 $convert->p_master->error($user->lang['CONV_ERROR_CONFIG_EMPTY'], __LINE__, __FILE__);
1255 return $convert_config;
1259 * Transfers the relevant configuration information from the source forum
1260 * The mapping of fields is specified in $config_schema, see convert_phpbb20.php for more details
1262 function restore_config($schema)
1264 global $db, $config;
1266 $convert_config = get_config();
1267 foreach ($schema['settings'] as $config_name => $src)
1269 if (preg_match('/(.*)\((.*)\)/', $src, $m))
1271 $var = (empty($m[2]) || empty($convert_config[$m[2]])) ? "''" : "'" . addslashes($convert_config[$m[2]]) . "'";
1272 $exec = '$config_value = ' . $m[1] . '(' . $var . ');';
1273 eval($exec);
1275 else
1277 $config_value = (isset($convert_config[$src])) ? $convert_config[$src] : '';
1280 if ($config_value !== '')
1282 // Most are...
1283 if (is_string($config_value))
1285 $config_value = truncate_string(utf8_htmlspecialchars($config_value), 255, 255, false);
1288 set_config($config_name, $config_value);
1294 * Update the count of PM's in custom folders for all users
1296 function update_folder_pm_count()
1298 global $db, $convert, $user;
1300 $sql = 'SELECT user_id, folder_id, COUNT(msg_id) as num_messages
1301 FROM ' . PRIVMSGS_TO_TABLE . '
1302 WHERE folder_id NOT IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ', ' . PRIVMSGS_INBOX . ', ' . PRIVMSGS_OUTBOX . ', ' . PRIVMSGS_SENTBOX . ')
1303 GROUP BY folder_id, user_id';
1304 $result = $db->sql_query($sql);
1306 while ($row = $db->sql_fetchrow($result))
1308 $db->sql_query('UPDATE ' . PRIVMSGS_FOLDER_TABLE . ' SET pm_count = ' . $row['num_messages'] . '
1309 WHERE user_id = ' . $row['user_id'] . ' AND folder_id = ' . $row['folder_id']);
1311 $db->sql_freeresult($result);
1314 // Functions mainly used by the main convertor script
1316 function path($path, $path_relative = true)
1318 if ($path === false)
1320 return '';
1323 if (substr($path, -1) != '/')
1325 $path .= '/';
1328 if (!$path_relative)
1330 return $path;
1333 if (substr($path, 0, 1) == '/')
1335 $path = substr($path, 1);
1338 return $path;
1342 * Extract the variables defined in a configuration file
1343 * @todo As noted by Xore we need to look at this from a security perspective
1345 function extract_variables_from_file($_filename)
1347 include($_filename);
1349 $vars = get_defined_vars();
1350 unset($vars['_filename']);
1352 return $vars;
1355 function get_path($src_path, $src_url, $test_file)
1357 global $config;
1359 $board_config = get_config();
1361 $test_file = preg_replace('/\.php$/i', '.' . PHP_EXT, $test_file);
1362 $src_path = path($src_path);
1364 if (@file_exists(PHPBB_ROOT_PATH . $src_path . $test_file))
1366 return $src_path;
1369 if (!empty($src_url) && !empty($board_config['server_name']))
1371 if (!preg_match('#https?://([^/]+)(.*)#i', $src_url, $m))
1373 return false;
1376 if ($m[1] != $board_config['server_name'])
1378 return false;
1381 $url_parts = explode('/', $m[2]);
1382 if (substr($src_url, -1) != '/')
1384 if (preg_match('/.*\.([a-z0-9]{3,4})$/i', $url_parts[sizeof($url_parts) - 1]))
1386 $url_parts[sizeof($url_parts) - 1] = '';
1388 else
1390 $url_parts[] = '';
1394 $script_path = $board_config['script_path'];
1395 if (substr($script_path, -1) == '/')
1397 $script_path = substr($script_path, 0, -1);
1400 $path_array = array();
1402 $phpbb_parts = explode('/', $script_path);
1403 for ($i = 0; $i < sizeof($url_parts); ++$i)
1405 if ($i < sizeof($phpbb_parts[$i]) && $url_parts[$i] == $phpbb_parts[$i])
1407 $path_array[] = $url_parts[$i];
1408 unset($url_parts[$i]);
1410 else
1412 $path = '';
1413 for ($j = $i; $j < sizeof($phpbb_parts); ++$j)
1415 $path .= '../';
1417 $path .= implode('/', $url_parts);
1418 break;
1422 if (!empty($path))
1424 if (@file_exists(PHPBB_ROOT_PATH . $path . $test_file))
1426 return $path;
1431 return false;
1434 function compare_table($tables, $tablename, &$prefixes)
1436 for ($i = 0, $table_size = sizeof($tables); $i < $table_size; ++$i)
1438 if (preg_match('/(.*)' . $tables[$i] . '$/', $tablename, $m))
1440 if (empty($m[1]))
1442 $m[1] = '*';
1445 if (isset($prefixes[$m[1]]))
1447 $prefixes[$m[1]]++;
1449 else
1451 $prefixes[$m[1]] = 1;
1458 * Grant permissions to a specified user or group
1460 * @param string $ug_type user|group|user_role|group_role
1461 * @param mixed $forum_id forum ids (array|int|0) -> 0 == all forums
1462 * @param mixed $ug_id [int] user_id|group_id : [string] usergroup name
1463 * @param mixed $acl_list [string] acl entry : [array] acl entries : [string] role entry
1464 * @param int $setting ACL_YES|ACL_NO|ACL_NEVER
1466 function mass_auth($ug_type, $forum_id, $ug_id, $acl_list, $setting = ACL_NO)
1468 global $db, $convert, $user, $config;
1469 static $acl_option_ids, $group_ids;
1471 if (($ug_type == 'group' || $ug_type == 'group_role') && is_string($ug_id))
1473 if (!isset($group_ids[$ug_id]))
1475 $sql = 'SELECT group_id
1476 FROM ' . GROUPS_TABLE . "
1477 WHERE group_name_clean = '" . $db->sql_escape(utf8_clean_string($ug_id)) . "'";
1478 $result = $db->sql_query_limit($sql, 1);
1479 $id = (int) $db->sql_fetchfield('group_id');
1480 $db->sql_freeresult($result);
1482 if (!$id)
1484 return;
1487 $group_ids[$ug_id] = $id;
1490 $ug_id = (int) $group_ids[$ug_id];
1493 $table = ($ug_type == 'user' || $ug_type == 'user_role') ? ACL_USERS_TABLE : ACL_GROUPS_TABLE;
1494 $id_field = ($ug_type == 'user' || $ug_type == 'user_role') ? 'user_id' : 'group_id';
1496 // Role based permissions are the simplest to handle so check for them first
1497 if ($ug_type == 'user_role' || $ug_type == 'group_role')
1499 if (is_numeric($forum_id))
1501 $sql = 'SELECT role_id
1502 FROM ' . ACL_ROLES_TABLE . "
1503 WHERE role_name = 'ROLE_" . $db->sql_escape($acl_list) . "'";
1504 $result = $db->sql_query_limit($sql, 1);
1505 $row = $db->sql_fetchrow($result);
1506 $db->sql_freeresult($result);
1508 // If we have no role id there is something wrong here
1509 if ($row)
1511 $sql = "INSERT INTO $table ($id_field, forum_id, auth_role_id) VALUES ($ug_id, $forum_id, " . $row['role_id'] . ')';
1512 $db->sql_query($sql);
1516 return;
1519 // Build correct parameters
1520 $auth = array();
1522 if (!is_array($acl_list))
1524 $auth = array($acl_list => $setting);
1526 else
1528 foreach ($acl_list as $auth_option)
1530 $auth[$auth_option] = $setting;
1533 unset($acl_list);
1535 if (!is_array($forum_id))
1537 $forum_id = array($forum_id);
1540 // Set any flags as required
1541 foreach ($auth as $auth_option => $acl_setting)
1543 $flag = substr($auth_option, 0, strpos($auth_option, '_') + 1);
1544 if (empty($auth[$flag]))
1546 $auth[$flag] = $acl_setting;
1550 if (!is_array($acl_option_ids) || empty($acl_option_ids))
1552 $sql = 'SELECT auth_option_id, auth_option
1553 FROM ' . ACL_OPTIONS_TABLE;
1554 $result = $db->sql_query($sql);
1556 while ($row = $db->sql_fetchrow($result))
1558 $acl_option_ids[$row['auth_option']] = $row['auth_option_id'];
1560 $db->sql_freeresult($result);
1563 $sql_forum = 'AND ' . $db->sql_in_set('a.forum_id', array_map('intval', $forum_id), false, true);
1565 $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";
1566 $result = $db->sql_query($sql);
1568 $cur_auth = array();
1569 while ($row = $db->sql_fetchrow($result))
1571 $cur_auth[$row['forum_id']][$row['auth_option_id']] = $row['auth_setting'];
1573 $db->sql_freeresult($result);
1575 $sql_ary = array();
1576 foreach ($forum_id as $forum)
1578 foreach ($auth as $auth_option => $setting)
1580 $auth_option_id = $acl_option_ids[$auth_option];
1582 if (!$auth_option_id)
1584 continue;
1587 switch ($setting)
1589 case ACL_NO:
1590 if (isset($cur_auth[$forum][$auth_option_id]))
1592 $sql_ary['delete'][] = "DELETE FROM $table
1593 WHERE forum_id = $forum
1594 AND auth_option_id = $auth_option_id
1595 AND $id_field = $ug_id";
1597 break;
1599 default:
1600 if (!isset($cur_auth[$forum][$auth_option_id]))
1602 $sql_ary['insert'][] = "$ug_id, $forum, $auth_option_id, $setting";
1604 else if ($cur_auth[$forum][$auth_option_id] != $setting)
1606 $sql_ary['update'][] = "UPDATE " . $table . "
1607 SET auth_setting = $setting
1608 WHERE $id_field = $ug_id
1609 AND forum_id = $forum
1610 AND auth_option_id = $auth_option_id";
1615 unset($cur_auth);
1617 $sql = '';
1618 foreach ($sql_ary as $sql_type => $sql_subary)
1620 switch ($sql_type)
1622 case 'insert':
1623 switch ($db->dbms_type)
1625 case 'mysql':
1626 $sql = 'VALUES ' . implode(', ', preg_replace('#^(.*?)$#', '(\1)', $sql_subary));
1627 break;
1629 case 'mssql':
1630 case 'sqlite':
1631 $sql = implode(' UNION ALL ', preg_replace('#^(.*?)$#', 'SELECT \1', $sql_subary));
1632 break;
1634 default:
1635 foreach ($sql_subary as $sql)
1637 $sql = "INSERT INTO $table ($id_field, forum_id, auth_option_id, auth_setting) VALUES ($sql)";
1638 $db->sql_query($sql);
1639 $sql = '';
1643 if ($sql != '')
1645 $sql = "INSERT INTO $table ($id_field, forum_id, auth_option_id, auth_setting) $sql";
1646 $db->sql_query($sql);
1648 break;
1650 case 'update':
1651 case 'delete':
1652 foreach ($sql_subary as $sql)
1654 $db->sql_query($sql);
1655 $sql = '';
1657 break;
1659 unset($sql_ary[$sql_type]);
1661 unset($sql_ary);
1666 * Update the count of unread private messages for all users
1668 function update_unread_count()
1670 global $db;
1672 $sql = 'SELECT user_id, COUNT(msg_id) as num_messages
1673 FROM ' . PRIVMSGS_TO_TABLE . '
1674 WHERE pm_unread = 1
1675 AND folder_id <> ' . PRIVMSGS_OUTBOX . '
1676 GROUP BY user_id';
1677 $result = $db->sql_query($sql);
1679 while ($row = $db->sql_fetchrow($result))
1681 $db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_unread_privmsg = ' . $row['num_messages'] . '
1682 WHERE user_id = ' . $row['user_id']);
1684 $db->sql_freeresult($result);
1688 * Add any of the pre-defined "special" groups which are missing from the database
1690 function add_default_groups()
1692 global $db;
1694 $default_groups = array(
1695 'GUESTS' => array('', 0, 0),
1696 'REGISTERED' => array('', 0, 0),
1697 'REGISTERED_COPPA' => array('', 0, 0),
1698 'GLOBAL_MODERATORS' => array('00AA00', 1, 0),
1699 'ADMINISTRATORS' => array('AA0000', 1, 1),
1700 'BOTS' => array('9E8DA7', 0, 0)
1703 $sql = 'SELECT *
1704 FROM ' . GROUPS_TABLE . '
1705 WHERE ' . $db->sql_in_set('group_name_clean', array_map('utf8_clean_string', array_keys($default_groups)));
1706 $result = $db->sql_query($sql);
1708 while ($row = $db->sql_fetchrow($result))
1710 unset($default_groups[strtoupper($row['group_name'])]);
1712 $db->sql_freeresult($result);
1714 $sql_ary = array();
1716 foreach ($default_groups as $name => $data)
1718 $sql_ary[] = array(
1719 'group_name' => (string) $name,
1720 'group_name_clean' => (string) utf8_clean_string($name),
1721 'group_desc' => '',
1722 'group_desc_uid' => '',
1723 'group_desc_bitfield' => '',
1724 'group_type' => GROUP_SPECIAL,
1725 'group_colour' => (string) $data[0],
1726 'group_legend' => (int) $data[1],
1727 'group_founder_manage' => (int) $data[2]
1731 if (sizeof($sql_ary))
1733 $db->sql_multi_insert(GROUPS_TABLE, $sql_ary);
1739 * Sync post count. We might need to do this in batches.
1741 function sync_post_count($offset, $limit)
1743 global $db;
1744 $sql = 'SELECT COUNT(post_id) AS num_posts, poster_id
1745 FROM ' . POSTS_TABLE . '
1746 WHERE post_postcount = 1
1747 GROUP BY poster_id
1748 ORDER BY poster_id';
1749 $result = $db->sql_query_limit($sql, $limit, $offset);
1751 while ($row = $db->sql_fetchrow($result))
1753 $db->sql_query('UPDATE ' . USERS_TABLE . " SET user_posts = {$row['num_posts']} WHERE user_id = {$row['poster_id']}");
1755 $db->sql_freeresult($result);
1759 * Add the search bots into the database
1760 * This code should be used in execute_last if the source database did not have bots
1761 * If you are converting bots this function should not be called
1762 * @todo We might want to look at sharing the bot list between the install code and this code for consistancy
1764 function add_bots()
1766 global $db, $convert, $user, $config;
1768 $db->sql_query($convert->truncate_statement . BOTS_TABLE);
1770 $sql = 'SELECT group_id FROM ' . GROUPS_TABLE . " WHERE group_name_clean = 'bots'";
1771 $result = $db->sql_query($sql);
1772 $group_id = (int) $db->sql_fetchfield('group_id', $result);
1773 $db->sql_freeresult($result);
1775 if (!$group_id)
1777 add_default_groups();
1779 $sql = 'SELECT group_id FROM ' . GROUPS_TABLE . " WHERE group_name_clean = 'bots'";
1780 $result = $db->sql_query($sql);
1781 $group_id = (int) $db->sql_fetchfield('group_id', $result);
1782 $db->sql_freeresult($result);
1784 if (!$group_id)
1786 global $install;
1787 $install->error($user->lang['CONV_ERROR_INCONSISTENT_GROUPS'], __LINE__, __FILE__);
1791 $bots = array(
1792 'AdsBot [Google]' => array('AdsBot-Google', ''),
1793 'Alexa [Bot]' => array('ia_archiver', ''),
1794 'Alta Vista [Bot]' => array('Scooter/', ''),
1795 'Ask Jeeves [Bot]' => array('Ask Jeeves', ''),
1796 'Baidu [Spider]' => array('Baiduspider+(', ''),
1797 'Exabot [Bot]' => array('Exabot/', ''),
1798 'FAST Enterprise [Crawler]' => array('FAST Enterprise Crawler', ''),
1799 'FAST WebCrawler [Crawler]' => array('FAST-WebCrawler/', ''),
1800 'Francis [Bot]' => array('http://www.neomo.de/', ''),
1801 'Gigabot [Bot]' => array('Gigabot/', ''),
1802 'Google Adsense [Bot]' => array('Mediapartners-Google', ''),
1803 'Google Desktop' => array('Google Desktop', ''),
1804 'Google Feedfetcher' => array('Feedfetcher-Google', ''),
1805 'Google [Bot]' => array('Googlebot', ''),
1806 'Heise IT-Markt [Crawler]' => array('heise-IT-Markt-Crawler', ''),
1807 'Heritrix [Crawler]' => array('heritrix/1.', ''),
1808 'IBM Research [Bot]' => array('ibm.com/cs/crawler', ''),
1809 'ICCrawler - ICjobs' => array('ICCrawler - ICjobs', ''),
1810 'ichiro [Crawler]' => array('ichiro/2', ''),
1811 'Majestic-12 [Bot]' => array('MJ12bot/', ''),
1812 'Metager [Bot]' => array('MetagerBot/', ''),
1813 'MSN NewsBlogs' => array('msnbot-NewsBlogs/', ''),
1814 'MSN [Bot]' => array('msnbot/', ''),
1815 'MSNbot Media' => array('msnbot-media/', ''),
1816 'NG-Search [Bot]' => array('NG-Search/', ''),
1817 'Nutch [Bot]' => array('http://lucene.apache.org/nutch/', ''),
1818 'Nutch/CVS [Bot]' => array('NutchCVS/', ''),
1819 'OmniExplorer [Bot]' => array('OmniExplorer_Bot/', ''),
1820 'Online link [Validator]' => array('online link validator', ''),
1821 'psbot [Picsearch]' => array('psbot/0', ''),
1822 'Seekport [Bot]' => array('Seekbot/', ''),
1823 'Sensis [Crawler]' => array('Sensis Web Crawler', ''),
1824 'SEO Crawler' => array('SEO search Crawler/', ''),
1825 'Seoma [Crawler]' => array('Seoma [SEO Crawler]', ''),
1826 'SEOSearch [Crawler]' => array('SEOsearch/', ''),
1827 'Snappy [Bot]' => array('Snappy/1.1 ( http://www.urltrends.com/ )', ''),
1828 'Steeler [Crawler]' => array('http://www.tkl.iis.u-tokyo.ac.jp/~crawler/', ''),
1829 'Synoo [Bot]' => array('SynooBot/', ''),
1830 'Telekom [Bot]' => array('crawleradmin.t-info@telekom.de', ''),
1831 'TurnitinBot [Bot]' => array('TurnitinBot/', ''),
1832 'Voyager [Bot]' => array('voyager/1.0', ''),
1833 'W3 [Sitesearch]' => array('W3 SiteSearch Crawler', ''),
1834 'W3C [Linkcheck]' => array('W3C-checklink/', ''),
1835 'W3C [Validator]' => array('W3C_*Validator', ''),
1836 'WiseNut [Bot]' => array('http://www.WISEnutbot.com', ''),
1837 'YaCy [Bot]' => array('yacybot', ''),
1838 'Yahoo MMCrawler [Bot]' => array('Yahoo-MMCrawler/', ''),
1839 'Yahoo Slurp [Bot]' => array('Yahoo! DE Slurp', ''),
1840 'Yahoo [Bot]' => array('Yahoo! Slurp', ''),
1841 'YahooSeeker [Bot]' => array('YahooSeeker/', ''),
1844 if (!function_exists('user_add'))
1846 include(PHPBB_ROOT_PATH . 'includes/functions_user.' . PHP_EXT);
1849 foreach ($bots as $bot_name => $bot_ary)
1851 $user_row = array(
1852 'user_type' => USER_IGNORE,
1853 'group_id' => $group_id,
1854 'username' => $bot_name,
1855 'user_regdate' => time(),
1856 'user_password' => '',
1857 'user_colour' => '9E8DA7',
1858 'user_email' => '',
1859 'user_lang' => $config['default_lang'],
1860 'user_style' => 1,
1861 'user_timezone' => 0,
1862 'user_allow_massemail' => 0,
1865 $user_id = user_add($user_row);
1867 if ($user_id)
1869 $sql = 'INSERT INTO ' . BOTS_TABLE . ' ' . $db->sql_build_array('INSERT', array(
1870 'bot_active' => 1,
1871 'bot_name' => $bot_name,
1872 'user_id' => $user_id,
1873 'bot_agent' => $bot_ary[0],
1874 'bot_ip' => $bot_ary[1])
1876 $db->sql_query($sql);
1882 * Update any dynamic configuration variables after the conversion is finished
1883 * @todo Confirm that this updates all relevant values since it has not necessarily been kept in sync with all changes
1885 function update_dynamic_config()
1887 global $db, $config;
1889 // Get latest username
1890 $sql = 'SELECT user_id, username, user_colour
1891 FROM ' . USERS_TABLE . '
1892 WHERE user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')';
1894 if (!empty($config['increment_user_id']))
1896 $sql .= ' AND user_id <> ' . $config['increment_user_id'];
1899 $sql .= ' ORDER BY user_id DESC';
1901 $result = $db->sql_query_limit($sql, 1);
1902 $row = $db->sql_fetchrow($result);
1903 $db->sql_freeresult($result);
1905 if ($row)
1907 set_config('newest_user_id', $row['user_id'], true);
1908 set_config('newest_username', $row['username'], true);
1909 set_config('newest_user_colour', $row['user_colour'], true);
1912 // Also do not reset record online user/date. There will be old data or the fresh data from the schema.
1913 // set_config('record_online_users', 1, true);
1914 // set_config('record_online_date', time(), true);
1916 $sql = 'SELECT COUNT(post_id) AS stat
1917 FROM ' . POSTS_TABLE . '
1918 WHERE post_approved = 1';
1919 $result = $db->sql_query($sql);
1920 $row = $db->sql_fetchrow($result);
1921 $db->sql_freeresult($result);
1923 set_config('num_posts', (int) $row['stat'], true);
1925 $sql = 'SELECT COUNT(topic_id) AS stat
1926 FROM ' . TOPICS_TABLE . '
1927 WHERE topic_approved = 1';
1928 $result = $db->sql_query($sql);
1929 $row = $db->sql_fetchrow($result);
1930 $db->sql_freeresult($result);
1932 set_config('num_topics', (int) $row['stat'], true);
1934 $sql = 'SELECT COUNT(user_id) AS stat
1935 FROM ' . USERS_TABLE . '
1936 WHERE user_type IN (' . USER_NORMAL . ',' . USER_FOUNDER . ')';
1937 $result = $db->sql_query($sql);
1938 $row = $db->sql_fetchrow($result);
1939 $db->sql_freeresult($result);
1941 set_config('num_users', (int) $row['stat'], true);
1943 $sql = 'SELECT COUNT(attach_id) as stat
1944 FROM ' . ATTACHMENTS_TABLE . '
1945 WHERE is_orphan = 0';
1946 $result = $db->sql_query($sql);
1947 set_config('num_files', (int) $db->sql_fetchfield('stat'), true);
1948 $db->sql_freeresult($result);
1950 $sql = 'SELECT SUM(filesize) as stat
1951 FROM ' . ATTACHMENTS_TABLE . '
1952 WHERE is_orphan = 0';
1953 $result = $db->sql_query($sql);
1954 set_config('upload_dir_size', (int) $db->sql_fetchfield('stat'), true);
1955 $db->sql_freeresult($result);
1958 * We do not resync users post counts - this can be done by the admin after conversion if wanted.
1959 $sql = 'SELECT COUNT(post_id) AS num_posts, poster_id
1960 FROM ' . POSTS_TABLE . '
1961 WHERE post_postcount = 1
1962 GROUP BY poster_id';
1963 $result = $db->sql_query($sql);
1965 while ($row = $db->sql_fetchrow($result))
1967 $db->sql_query('UPDATE ' . USERS_TABLE . " SET user_posts = {$row['num_posts']} WHERE user_id = {$row['poster_id']}");
1969 $db->sql_freeresult($result);
1974 * Updates topics_posted entries
1976 function update_topics_posted()
1978 global $db, $config;
1980 if ($db->truncate)
1982 $db->sql_query('DELETE FROM ' . TOPICS_POSTED_TABLE);
1984 else
1986 $db->sql_query('TRUNCATE TABLE ' . TOPICS_POSTED_TABLE);
1989 // This can get really nasty... therefore we only do the last six months
1990 $get_from_time = time() - (6 * 4 * 7 * 24 * 60 * 60);
1992 // Select forum ids, do not include categories
1993 $sql = 'SELECT forum_id
1994 FROM ' . FORUMS_TABLE . '
1995 WHERE forum_type <> ' . FORUM_CAT;
1996 $result = $db->sql_query($sql);
1998 $forum_ids = array();
1999 while ($row = $db->sql_fetchrow($result))
2001 $forum_ids[] = $row['forum_id'];
2003 $db->sql_freeresult($result);
2005 // Any global announcements? ;)
2006 $forum_ids[] = 0;
2008 // Now go through the forums and get us some topics...
2009 foreach ($forum_ids as $forum_id)
2011 $sql = 'SELECT p.poster_id, p.topic_id
2012 FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t
2013 WHERE t.forum_id = ' . $forum_id . '
2014 AND t.topic_moved_id = 0
2015 AND t.topic_last_post_time > ' . $get_from_time . '
2016 AND t.topic_id = p.topic_id
2017 AND p.poster_id <> ' . ANONYMOUS . '
2018 GROUP BY p.poster_id, p.topic_id';
2019 $result = $db->sql_query($sql);
2021 $posted = array();
2022 while ($row = $db->sql_fetchrow($result))
2024 $posted[$row['poster_id']][] = $row['topic_id'];
2026 $db->sql_freeresult($result);
2028 $sql_ary = array();
2029 foreach ($posted as $user_id => $topic_row)
2031 foreach ($topic_row as $topic_id)
2033 $sql_ary[] = array(
2034 'user_id' => (int) $user_id,
2035 'topic_id' => (int) $topic_id,
2036 'topic_posted' => 1,
2040 unset($posted);
2042 if (sizeof($sql_ary))
2044 $db->sql_multi_insert(TOPICS_POSTED_TABLE, $sql_ary);
2050 * Ensure that all users have a default group specified and update related information such as their colour
2052 function fix_empty_primary_groups()
2054 global $db;
2056 // Set group ids for users not already having it
2057 $sql = 'UPDATE ' . USERS_TABLE . ' SET group_id = ' . get_group_id('registered') . '
2058 WHERE group_id = 0 AND user_type = ' . USER_INACTIVE;
2059 $db->sql_query($sql);
2061 $sql = 'UPDATE ' . USERS_TABLE . ' SET group_id = ' . get_group_id('registered') . '
2062 WHERE group_id = 0 AND user_type = ' . USER_NORMAL;
2063 $db->sql_query($sql);
2065 $db->sql_query('UPDATE ' . USERS_TABLE . ' SET group_id = ' . get_group_id('guests') . ' WHERE user_id = ' . ANONYMOUS);
2067 $sql = 'SELECT user_id FROM ' . USER_GROUP_TABLE . ' WHERE group_id = ' . get_group_id('administrators');
2068 $result = $db->sql_query($sql);
2070 $user_ids = array();
2071 while ($row = $db->sql_fetchrow($result))
2073 $user_ids[] = $row['user_id'];
2075 $db->sql_freeresult($result);
2077 if (sizeof($user_ids))
2079 $db->sql_query('UPDATE ' . USERS_TABLE . ' SET group_id = ' . get_group_id('administrators') . '
2080 WHERE group_id = 0 AND ' . $db->sql_in_set('user_id', $user_ids));
2083 $sql = 'SELECT user_id FROM ' . USER_GROUP_TABLE . ' WHERE group_id = ' . get_group_id('global_moderators');
2085 $user_ids = array();
2086 while ($row = $db->sql_fetchrow($result))
2088 $user_ids[] = $row['user_id'];
2090 $db->sql_freeresult($result);
2092 if (sizeof($user_ids))
2094 $db->sql_query('UPDATE ' . USERS_TABLE . ' SET group_id = ' . get_group_id('global_moderators') . '
2095 WHERE group_id = 0 AND ' . $db->sql_in_set('user_id', $user_ids));
2098 // Set user colour
2099 $sql = 'SELECT group_id, group_colour FROM ' . GROUPS_TABLE . "
2100 WHERE group_colour <> ''";
2101 $result = $db->sql_query($sql);
2103 while ($row = $db->sql_fetchrow($result))
2105 $db->sql_query('UPDATE ' . USERS_TABLE . " SET user_colour = '{$row['group_colour']}' WHERE group_id = {$row['group_id']}");
2107 $db->sql_freeresult($result);
2111 * Cleanly remove invalid user entries after converting the users table...
2113 function remove_invalid_users()
2115 global $convert, $db;
2117 // username_clean is UNIQUE
2118 $sql = 'SELECT user_id
2119 FROM ' . USERS_TABLE . "
2120 WHERE username_clean = ''";
2121 $result = $db->sql_query($sql);
2122 $row = $db->sql_fetchrow($result);
2123 $db->sql_freeresult($result);
2125 if ($row)
2127 if (!function_exists('user_delete'))
2129 include(PHPBB_ROOT_PATH . 'includes/functions_user.' . PHP_EXT);
2132 user_delete('remove', $row['user_id']);
2136 function convert_bbcode($message, $convert_size = true, $extended_bbcodes = false)
2138 static $orig, $repl, $origx, $replx, $str_from, $str_to;
2140 if (empty($orig))
2142 $orig = $repl = array();
2144 $orig[] = '#\[(php|sql)\](.*?)\[/(php|sql)\]#is';
2145 $repl[] = '[code]\2[/code]';
2147 $orig[] = '#\[font=[^\]]+\](.*?)\[/font\]#is';
2148 $repl[] = '\1';
2150 $orig[] = '#\[align=[a-z]+\](.*?)\[/align\]#is';
2151 $repl[] = '\1';
2153 $orig[] = '#\[/list=.*?\]#is';
2154 $repl[] = '[/list]';
2156 $origx = array(
2157 '#\[glow[^\]]+\](.*?)\[/glow\]#is',
2158 '#\[shadow[^\]]+\](.*?)\[/shadow\]#is',
2159 '#\[flash[^\]]+\](.*?)\[/flash\]#is'
2162 $replx = array(
2163 '\1',
2164 '\1',
2165 '[url=\1]Flash[/url]'
2168 $str_from = array(
2169 '[ftp]', '[/ftp]',
2170 '[ftp=', '[/ftp]',
2171 '[pre]', '[/pre]',
2172 '[table]', '[/table]',
2173 '[td]', '[/td]',
2174 '[tr]', '[/tr]',
2175 '[s]', '[/s]',
2176 '[left]', '[/left]',
2177 '[right]', '[/right]',
2178 '[center]', '[/center]',
2179 '[sub]', '[/sub]',
2180 '[sup]', '[/sup]',
2181 '[tt]', '[/tt]',
2182 '[move]', '[/move]',
2183 '[hr]'
2186 $str_to = array(
2187 '[url]', '[/url]',
2188 '[url=', '[/url]',
2189 '[code]', '[/code]',
2190 "\n", '',
2191 '', '',
2192 "\n", '',
2193 '', '',
2194 '', '',
2195 '', '',
2196 '', '',
2197 '', '',
2198 '', '',
2199 '', '',
2200 '', '',
2201 "\n\n"
2204 for ($i = 0; $i < sizeof($str_from); ++$i)
2206 $origx[] = '#\\' . str_replace(']', '\\]', $str_from[$i]) . '#is';
2207 $replx[] = $str_to[$i];
2211 if (preg_match_all('#\[email=([^\]]+)\](.*?)\[/email\]#i', $message, $m))
2213 for ($i = 0; $i < sizeof($m[1]); ++$i)
2215 if ($m[1][$i] == $m[2][$i])
2217 $message = str_replace($m[0][$i], '[email]' . $m[1][$i] . '[/email]', $message);
2219 else
2221 $message = str_replace($m[0][$i], $m[2][$i] . ' ([email]' . $m[1][$i] . '[/email])', $message);
2226 if ($convert_size && preg_match('#\[size=[0-9]+\].*?\[/size\]#i', $message))
2228 $size = array(9, 9, 12, 15, 18, 24, 29, 29, 29, 29);
2229 $message = preg_replace('#\[size=([0-9]+)\](.*?)\[/size\]#i', '[size=\1]\2[/size]', $message);
2230 $message = preg_replace('#\[size=[0-9]{2,}\](.*?)\[/size\]#i', '[size=29]\1[/size]', $message);
2232 for ($i = sizeof($size); $i; )
2234 $i--;
2235 $message = str_replace('[size=' . $i . ']', '[size=' . $size[$i] . ']', $message);
2239 if ($extended_bbcodes)
2241 $message = preg_replace($origx, $replx, $message);
2244 $message = preg_replace($orig, $repl, $message);
2245 return $message;
2249 function copy_file($src, $trg, $overwrite = false, $die_on_failure = true, $source_relative_path = true)
2251 global $convert, $config, $user, $db;
2253 if (substr($trg, -1) == '/')
2255 $trg .= basename($src);
2257 $src_path = relative_base($src, $source_relative_path, __LINE__, __FILE__);
2258 $trg_path = $trg;
2260 if (!$overwrite && @file_exists($trg_path))
2262 return true;
2265 if (!@file_exists($src_path))
2267 return;
2270 $path = PHPBB_ROOT_PATH;
2271 $parts = explode('/', $trg);
2272 unset($parts[sizeof($parts) - 1]);
2274 for ($i = 0; $i < sizeof($parts); ++$i)
2276 $path .= $parts[$i] . '/';
2278 if (!is_dir($path))
2280 @mkdir($path, 0777);
2284 if (!is_writable($path))
2286 @chmod($path, 0777);
2289 if (!@copy($src_path, PHPBB_ROOT_PATH . $trg_path))
2291 $convert->p_master->error(sprintf($user->lang['COULD_NOT_COPY'], $src_path, PHPBB_ROOT_PATH . $trg_path), __LINE__, __FILE__, !$die_on_failure);
2292 return;
2295 if ($perm = @fileperms($src_path))
2297 @chmod(PHPBB_ROOT_PATH . $trg_path, $perm);
2300 return true;
2303 function copy_dir($src, $trg, $copy_subdirs = true, $overwrite = false, $die_on_failure = true, $source_relative_path = true)
2305 global $convert, $config, $user, $db;
2307 $dirlist = $filelist = $bad_dirs = array();
2308 $src = path($src, $source_relative_path);
2309 $trg = path($trg);
2310 $src_path = relative_base($src, $source_relative_path, __LINE__, __FILE__);
2311 $trg_path = PHPBB_ROOT_PATH . $trg;
2313 if (!is_dir($trg_path))
2315 @mkdir($trg_path, 0777);
2316 @chmod($trg_path, 0777);
2319 if (!@is_writable($trg_path))
2321 $bad_dirs[] = path($config['script_path']) . $trg;
2324 if ($handle = @opendir($src_path))
2326 while ($entry = readdir($handle))
2328 if ($entry[0] == '.' || $entry == 'CVS' || $entry == 'index.htm')
2330 continue;
2333 if (is_dir($src_path . $entry))
2335 $dirlist[] = $entry;
2337 else
2339 $filelist[] = $entry;
2342 closedir($handle);
2344 else if ($dir = @dir($src_path))
2346 while ($entry = $dir->read())
2348 if ($entry[0] == '.' || $entry == 'CVS' || $entry == 'index.htm')
2350 continue;
2353 if (is_dir($src_path . $entry))
2355 $dirlist[] = $entry;
2357 else
2359 $filelist[] = $entry;
2362 $dir->close();
2364 else
2366 $convert->p_master->error(sprintf($user->lang['CONV_ERROR_COULD_NOT_READ'], relative_base($src, $source_relative_path)), __LINE__, __FILE__);
2369 if ($copy_subdirs)
2371 for ($i = 0; $i < sizeof($dirlist); ++$i)
2373 $dir = $dirlist[$i];
2375 if ($dir == 'CVS')
2377 continue;
2380 if (!is_dir($trg_path . $dir))
2382 @mkdir($trg_path . $dir, 0777);
2383 @chmod($trg_path . $dir, 0777);
2386 if (!@is_writable($trg_path . $dir))
2388 $bad_dirs[] = $trg . $dir;
2389 $bad_dirs[] = $trg_path . $dir;
2392 if (!sizeof($bad_dirs))
2394 copy_dir($src . $dir, $trg . $dir, true, $overwrite, $die_on_failure, $source_relative_path);
2399 if (sizeof($bad_dirs))
2401 $str = (sizeof($bad_dirs) == 1) ? $user->lang['MAKE_FOLDER_WRITABLE'] : $user->lang['MAKE_FOLDERS_WRITABLE'];
2402 sort($bad_dirs);
2403 $convert->p_master->error(sprintf($str, implode('<br />', $bad_dirs)), __LINE__, __FILE__);
2406 for ($i = 0; $i < sizeof($filelist); ++$i)
2408 copy_file($src . $filelist[$i], $trg . $filelist[$i], $overwrite, $die_on_failure, $source_relative_path);
2412 function relative_base($path, $is_relative = true, $line = false, $file = false)
2414 global $convert, $config, $user, $db;
2416 if (!$is_relative)
2418 return $path;
2421 if (empty($convert->options['forum_path']) && $is_relative)
2423 $line = $line ? $line : __LINE__;
2424 $file = $file ? $file : __FILE__;
2426 $convert->p_master->error($user->lang['CONV_ERROR_NO_FORUM_PATH'], $line, $file);
2429 return $convert->options['forum_path'] . '/' . $path;
2432 function get_smiley_display()
2434 static $smiley_count = 0;
2435 $smiley_count++;
2436 return ($smiley_count < 50) ? 1 : 0;
2440 function fill_dateformat($user_dateformat)
2442 global $config;
2444 return ((empty($user_dateformat)) ? $config['default_dateformat'] : $user_dateformat);