/[drupal]/contributions/modules/vbtodrupal/vbtodrupal.module
ViewVC logotype

Contents of /contributions/modules/vbtodrupal/vbtodrupal.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.4 - (show annotations) (download) (as text)
Mon Nov 5 21:54:03 2007 UTC (2 years ago) by liammcdermott
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-5
Changes since 1.3: +2 -1 lines
File MIME type: text/x-php
Small fixes before release.
1 <?php
2 // $Id: vbtodrupal.module,v 1.3 2007/11/05 19:55:51 liammcdermott Exp $
3
4 define('VBTODRUPAL_DEFAULT_VB_DB_PREFIX', 'vb_');
5 // We're allowing 2 hours for migration by default (this is in seconds)
6 define('VBTODRUPAL_ALLOWED_TIME_FOR_MIGRATE', 7200);
7 // Arbitrary number to add to database id values
8 // stops imported records from interfering with existing ones
9 define('VBTODRUPAL_ADD_TO_IDS', 1000000);
10
11 /**
12 * Implementation of hook_menu()
13 */
14 function vbtodrupal_menu($may_cache) {
15 $items = array();
16
17 if(!$may_cache) {
18 $items[] = array(
19 'path' => 'admin/build/vbtodrupal',
20 'title' => t('vB to Drupal'),
21 'description' => t('Convert a vBulletin forum into a Drupal forum'),
22 'access' => user_access('migrate vbulletin'),
23 'callback' => 'vbtodrupal_gui',
24 'callback arguments' => 'configure',
25 'type' => MENU_NORMAL_ITEM);
26 $items[] = array(
27 'path' => 'admin/build/vbtodrupal/configure',
28 'title' => t('Configure'),
29 'access' => user_access('migrate vbulletin'),
30 'type' => MENU_DEFAULT_LOCAL_TASK,
31 'weight' => -10);
32 $items[] = array(
33 'path' => 'admin/build/vbtodrupal/test',
34 'title' => t('Test'),
35 'access' => user_access('migrate vbulletin'),
36 'callback' => 'vbtodrupal_gui',
37 'callback arguments' => 'test',
38 'type' => MENU_LOCAL_TASK,
39 'weight' => -8);
40 $items[] = array(
41 'path' => 'admin/build/vbtodrupal/migrate',
42 'title' => t('Migrate data'),
43 'access' => user_access('migrate vbulletin'),
44 'callback' => 'vbtodrupal_gui',
45 'callback arguments' => 'migrate',
46 'type' => MENU_LOCAL_TASK);
47 }
48 return $items;
49 }
50
51 /**
52 * Implementation of hook_perm()
53 */
54 function vbtodrupal_perm() {
55 return array('migrate vbulletin');
56 }
57
58 function vbtodrupal_gui($type) {
59
60 switch ($type) {
61 case 'configure':
62 $output .= '<p><em>'. t('Note: if when clicking on the <strong>Test tab</strong> Drupal prints lots of errors these settings are wrong. Simply <strong>click the back button</strong> in your browser to check the configuration.') .'</em></p>';
63 $output .= drupal_get_form('vbtodrupal_settings');
64 break;
65 case 'test':
66 $output .= '<h3>'. t('Testing for vBulletin tables') .'</h3>';
67 $tablestocheck = array('thread', 'post', 'user', 'pm');
68 $tablecheck = _vbtodrupal_check_tables($tablestocheck);
69 $output .= $tablecheck['html'];
70 if (!$tablecheck['result']) {
71 $output .= '<p><strong>'. t('Check failed: The database settings are probably incorrect') .'</strong></p>';
72 }
73 else {
74 $output .= '<p>'. t('Tables check passed!') .'</p>';
75 }
76 $output .= '<h3>'. t('Testing for PHP safe mode') .'</h3>';
77 if (ini_get('safe_mode')) {
78 $output .= '<p><strong>'. t('Check failed: importing will probably time out due to restrictions on PHP. Please see your hosts/system administrator to fix this issue (set safe_mode to off in php.ini)') .'</strong></p>';
79 }
80 else {
81 $output .= '<p>'. t('Safe mode check passed!') .'</p>';
82 }
83 $output .= '<h3>'. t('Testing whether pictures are enabled') .'</h3>';
84 if (!variable_get('user_pictures', 0)) {
85 $output .= '<p><strong>'. t('Check failed: user pictures are not enabled, please enable them in the Administration area or avatar import will fail!') .'</strong></p>';
86 }
87 else {
88 $output .= '<p>'. t('User picture check passed!') .'</p>';
89 }
90 $output .= '<h3>'. t('Testing Forum module has been enabled correctly') .'</h3>';
91
92 // Grab the vid for the Forums vocabulary.
93 $sql = 'SELECT vid FROM {vocabulary} WHERE module="forum";';
94 $forum_vid = db_fetch_object(db_query($sql));
95 // Sometimes Drupal hasn't created a vocabulary entry for the forums. If we
96 // don't trap the error a SQL warning will be generated.
97 if (!$forum_vid->vid) {
98 $output .= '<p><strong>'. t('Check failed: you may need to reinstall the Forum module, then visit its Admin pages. This is due to a quirk in the Forum module.') .'</strong></p>';
99 }
100 else {
101 $output .= '<p>'. t('Forum check passed!') .'</p>';
102 }
103
104
105 $output .= '<p>'. t('If the checks have succeeded you may continue with the migration') .'</p>';
106 break;
107 case 'migrate':
108 // Change time allowed for script to run
109 if (!ini_get('safe_mode')) {
110 set_time_limit(VBTODRUPAL_ALLOWED_TIME_FOR_MIGRATE);
111 }
112 print '<ol>';
113 // Users
114 print '<li>'. t('Importing users...') .'</li>';
115 flush();
116 _vbtodrupal_convusers();
117 // Forums
118 print '<li>'. t('Importing forums...') .'</li>';
119 flush();
120 _vbtodrupal_convforums();
121 // Threads
122 print '<li>'. t('Importing threads...') .'</li>';
123 flush();
124 _vbtodrupal_convthreads();
125 // Posts
126 print '<li>'. t('Importing posts...') .'</li>';
127 flush();
128 _vbtodrupal_convposts();
129 // Polls
130 print '<li>'. t('Importing polls...') .'</li>';
131 flush();
132 _vbtodrupal_convpolls();
133 // Files
134 print '<li>'. t('Importing files...') .'</li>';
135 flush();
136 _vbtodrupal_convfiles();
137 // PMs (only imported if privatemsg module is installed)
138 if (module_exists('privatemsg')) {
139 print '<li>'. t('Importing private messages...') .'</li>';
140 flush();
141 _vbtodrupal_convpms();
142 }
143 else {
144 print '<li><strong>'. t('Privatemsg module not installed: skipping Private messages import.') .'</strong></li>';
145 }
146 // Rebuild stats
147 print '<li>'. t('Rebuilding stats...') .'</li>';
148 flush();
149 _vbtodrupal_updatestats();
150 // Fix vBulletin BBCode implementation
151 print '<li>'. t('Fixing BBCode...') .'</li>';
152 flush();
153 _vbtodrupal_fixbbcode();
154 print '</ol>';
155 print '<p><a href="./">Finished, go back</a></p>';
156 flush();
157 $message .= '<h3>Migration complete!</h3>';
158 $message .= '<p>Have a nice cup of tea and pat yourself on the back, you moved off vBulletin!</p>';
159 drupal_set_message($message);
160 exit;
161 break;
162 }
163 return $output;
164 }
165
166 function vbtodrupal_settings() {
167 global $db_url;
168 if (is_array($db_url)) {
169 $db_url_for_form = $db_url[0];
170 }
171 else {
172 $db_url_for_form = $db_url;
173 }
174
175 $form['vbtodrupal_db_url'] = array(
176 '#type' => 'textfield',
177 '#title' => t('Where is the vBulletin database?'),
178 '#required' => TRUE,
179 '#default_value' => variable_get('vbtodrupal_db_url', $db_url_for_form),
180 );
181 $form['vbtodrupal_db_prefix'] = array(
182 '#type' => 'textfield',
183 '#title' => t('Table name prefix'),
184 '#default_value' => variable_get('vbtodrupal_db_prefix', VBTODRUPAL_DEFAULT_VB_DB_PREFIX),
185 );
186 return system_settings_form($form);
187 }
188
189 /**
190 * Setup database connection for vbtodrupal
191 */
192 function _vbtodrupal_db_setup() {
193 global $db_url;
194 global $db_prefix;
195
196 // Test whether db_url array has been constructed already
197 if ($db_url['vb'] != variable_get('vbtodrupal_db_url', $db_url)) {
198 $db_url2['vb'] = variable_get('vbtodrupal_db_url', $db_url);
199 $db_url2['default'] = $db_url;
200 $db_url =& $db_url2;
201 $GLOBALS['db_url'] =& $db_url2;
202 }
203
204 if (variable_get('vbtodrupal_db_prefix', '') != $db_prefix) {
205 // If the prefix of the vBulletin database tables is different to
206 // the prefix of the Drupal database tables...
207 variable_set('vbtodrupal_default_db_prefix', $db_prefix);
208 $GLOBALS['db_prefix'] = variable_get('vbtodrupal_db_prefix', VBTODRUPAL_DEFAULT_VB_DB_PREFIX);
209 // Store the original (for restore function) and switch the prefix
210 }
211
212 // Get the Drupal db name from db_url
213 $drupal_db_name = explode('/', $db_url['default']);
214 $drupal_db_name = $drupal_db_name[count($drupal_db_name)-1];
215 $drupal_db_prefix = variable_get('vbtodrupal_default_db_prefix', $db_prefix);
216 db_set_active('vb');
217 return array(
218 'drupal_db_name' => $drupal_db_name,
219 'drupal_db_prefix' => $drupal_db_prefix,
220 );
221 }
222
223 /**
224 * Restore database connection for normal Drupal operations
225 * Note: a restore should never be attempted without a setup!
226 */
227 function _vbtodrupal_db_restore() {
228 global $db_url;
229 global $db_prefix;
230
231 if (variable_get('vbtodrupal_default_db_prefix', '') != $db_prefix) {
232 // If the prefix of the Drupal database tables is different to
233 // the current prefix then retrieve old prefix
234 $GLOBALS['db_prefix'] = variable_get('vbtodrupal_default_db_prefix', $db_prefix);
235 }
236 db_set_active('default');
237 }
238
239 /**
240 * Check if the sql tables are installed.
241 * Thank you to the phpbb2drupal project
242 * for this function
243 *
244 * @return array
245 * $out['html'] = formatted html.
246 * $out['result'] = boolean.
247 */
248 function _vbtodrupal_check_tables($tables = array()) {
249 global $db_prefix;
250
251 $out['html'] = '<ul>';
252 $out['result']= 1;
253 foreach ($tables as $table) {
254 _vbtodrupal_db_setup();
255 if ($db_prefix) {
256 $table = db_prefix_tables('{'.$table.'}');
257 }
258 if ($GLOBALS['db_type'] == 'pgsql') {
259 $query = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name LIKE '%s'";
260 }
261 else {
262 $query = "SHOW TABLES LIKE '%s'";
263 }
264 $result = db_query($query, $table);
265 _vbtodrupal_db_restore();
266 $result = db_num_rows($result);
267 if ($result) {
268 $out['html'] .= '<li>'. t('Table %table: Yes', array('%table' => $table)) .'</li>';
269 }
270 else {
271 $out['html'] .= '<li><span class="marker">'. t('Table <strong>%table</strong> does not exist!', array('%table' => $table)) .'</span></li>';
272 $out['result']= 0;
273 }
274 }
275 $out['html'] .= '</ul>';
276 return $out;
277 }
278
279 /**
280 * An copy of db_prefix_tables that uses a parameter instead of a global
281 * for $db_prefix.
282 *
283 * @param $sql
284 * A string containing a partial or entire SQL query.
285 * @param $db_prefix
286 * An array or string containing the database table prefix.
287 *
288 * @return
289 * The properly-prefixed string.
290 */
291 function _vbtodrupal_db_prefix_tables($sql, $db_prefix, $db_name) {
292 if (is_array($db_name)) {
293 $db_name = $db_name['default'];
294 }
295 if (is_array($db_prefix)) {
296 if (array_key_exists('default', $db_prefix)) {
297 $tmp = $db_prefix;
298 unset($tmp['default']);
299 foreach ($tmp as $key => $val) {
300 $sql = strtr($sql, array('{'. $key .'}' => $db_name .'.'. $val . $key));
301 }
302 return strtr($sql, array('{' => $db_name .'.'. $db_prefix['default'], '}' => ''));
303 }
304 else {
305 foreach ($db_prefix as $key => $val) {
306 $sql = strtr($sql, array('{'. $key .'}' => $db_name .'.'. $val . $key));
307 }
308 return strtr($sql, array('{' => '', '}' => ''));
309 }
310 }
311 else {
312 return strtr($sql, array('{' => $db_name .'.'. $db_prefix, '}' => ''));
313 }
314 }
315
316 /**
317 * Helper function that does the donkey work of
318 * migrating users
319 */
320 function _vbtodrupal_convusers() {
321 // create profile fields for icq, aim, msn...etc
322 $query = 'INSERT IGNORE INTO {profile_fields} (title, name, explanation, category, page, type, weight, required, register, visibility, options) VALUES ';
323
324 $query .= "('YIM', 'user_yim', '', 'Contact', '', 'textfield', 0, 0, 1, 2, '')";
325 $query .= ",('MSN', 'user_msn', '', 'Contact', '', 'textfield', 0, 0, 1, 2, '')";
326 $query .= ",('Skype', 'user_skype', '', 'Contact', '', 'textfield', 0, 0, 1, 2, '')";
327 $query .= ",('AIM', 'user_aim', '', 'Contact', '', 'textfield', 0, 0, 1, 2, '')";
328 $query .= ",('icq', 'user_icq', '', 'Contact', '', 'textfield', 0, 0, 1, 2, '')";
329 $query .= ",('Website', 'user_website', '', 'Contact', '', 'url', 0, 0, 1, 2, '')";
330 $query .= ",('Location', 'user_from', '', 'Personal', '', 'textfield', 0, 0, 1, 2, '')";
331 $query .= ",('Occupation', 'user_occ', '', 'Personal', '', 'textfield', 0, 0, 1, 2, '')";
332 $query .= ",('Interests', 'user_interests', '', 'Personal', '', 'textfield', 0, 0, 1, 2, '')";
333 $query .= ",('Gender', 'user_gender', '', 'Personal', '', 'selection', 0, 0, 1, 2, 'Male
334 Female')";
335 db_query($query);
336
337 $drupal_settings = _vbtodrupal_db_setup();
338 $drupal_db_name = $drupal_settings['drupal_db_name'];
339 $drupal_db_prefix = $drupal_settings['drupal_db_prefix'];
340
341 // Signatures
342 $sql = 'INSERT IGNORE INTO %s (uid, signature) ';
343 $sql .= 'SELECT {user}.userid+%d, signature ';
344 $sql .= 'FROM {user} INNER JOIN {usertextfield} ON {user}.userid={usertextfield}.userid ';
345 $sql .= 'WHERE signature IS NOT NULL ';
346 db_query($sql,
347 _vbtodrupal_db_prefix_tables('{users_signature}', $drupal_db_prefix, $drupal_db_name),
348 VBTODRUPAL_ADD_TO_IDS);
349
350 // Main user table
351 $file_path = variable_get('file_directory_path', 'files');
352 $picture_path = variable_get('user_picture_path', 'pictures');
353 $sql = 'INSERT IGNORE INTO %s (uid, name, pass, mail, created, access, login, status, timezone, picture) ';
354 // When avatars are imported from the vB database the filename is prepended with the userid to prevent duplicate file names
355 $sql .= 'SELECT {user}.userid+%d, username, password, email, joindate, lastactivity, lastvisit, 1, timezoneoffset*60*60, CONCAT(\'%s/%s/\', {user}.userid+%d, \'_\', filename) ';
356 $sql .= 'FROM {user} LEFT OUTER JOIN {usertextfield} ON {user}.userid={usertextfield}.userid ';
357 $sql .= ' LEFT OUTER JOIN {customavatar} ON {user}.userid={customavatar}.userid;';
358 db_query($sql,
359 _vbtodrupal_db_prefix_tables('{users}', $drupal_db_prefix, $drupal_db_name),
360 VBTODRUPAL_ADD_TO_IDS,
361 $file_path,
362 $picture_path,
363 VBTODRUPAL_ADD_TO_IDS);
364
365 // Import user salt for vBulletin password auth service.
366 // This query is the reason this module depends upon vbpassword
367 // (because this table has to exist to import to)
368 $sql = 'INSERT IGNORE INTO %s (uid, salt, drupal_updated) ';
369 $sql .= 'SELECT userid+%d, salt, 0 ';
370 $sql .= 'FROM {user};';
371 db_query($sql,
372 _vbtodrupal_db_prefix_tables('{vbuser_salt}', $drupal_db_prefix, $drupal_db_name),
373 VBTODRUPAL_ADD_TO_IDS);
374
375 // Yahoo
376 $sql = 'INSERT IGNORE INTO %s (fid, uid, value) ';
377 $sql .= 'SELECT fid, userid+%d, yahoo ';
378 $sql .= 'FROM {user}, %s ';
379 $sql .= 'WHERE name="user_yim" AND yahoo<>"";';
380 db_query($sql,
381 _vbtodrupal_db_prefix_tables('{profile_values}', $drupal_db_prefix, $drupal_db_name),
382 VBTODRUPAL_ADD_TO_IDS,
383 _vbtodrupal_db_prefix_tables('{profile_fields}', $drupal_db_prefix, $drupal_db_name));
384
385 // MSN
386 $sql = 'INSERT IGNORE INTO %s (fid, uid, value) ';
387 $sql .= 'SELECT fid, userid+%d, msn ';
388 $sql .= 'FROM {user}, %s ';
389 $sql .= 'WHERE name="user_msn" AND msn<>"";';
390 db_query($sql,
391 _vbtodrupal_db_prefix_tables('{profile_values}', $drupal_db_prefix, $drupal_db_name),
392 VBTODRUPAL_ADD_TO_IDS,
393 _vbtodrupal_db_prefix_tables('{profile_fields}', $drupal_db_prefix, $drupal_db_name));
394
395 // Skype
396 $sql = 'INSERT IGNORE INTO %s (fid, uid, value) ';
397 $sql .= 'SELECT fid, userid+%d, skype ';
398 $sql .= 'FROM {user}, %s ';
399 $sql .= 'WHERE name="user_skype" AND skype<>"";';
400 db_query($sql,
401 _vbtodrupal_db_prefix_tables('{profile_values}', $drupal_db_prefix, $drupal_db_name),
402 VBTODRUPAL_ADD_TO_IDS,
403 _vbtodrupal_db_prefix_tables('{profile_fields}', $drupal_db_prefix, $drupal_db_name));
404
405 // AIM
406 $sql = 'INSERT IGNORE INTO %s (fid, uid, value) ';
407 $sql .= 'SELECT fid, userid+%d, aim ';
408 $sql .= 'FROM {user}, %s ';
409 $sql .= 'WHERE name="user_aim" AND aim<>"";';
410 db_query($sql,
411 _vbtodrupal_db_prefix_tables('{profile_values}', $drupal_db_prefix, $drupal_db_name),
412 VBTODRUPAL_ADD_TO_IDS,
413 _vbtodrupal_db_prefix_tables('{profile_fields}', $drupal_db_prefix, $drupal_db_name));
414
415 // ICQ
416 $sql = 'INSERT IGNORE INTO %s (fid, uid, value) ';
417 $sql .= 'SELECT fid, userid+%d, icq ';
418 $sql .= 'FROM {user}, %s ';
419 $sql .= 'WHERE name="user_icq" AND icq<>"";';
420 db_query($sql,
421 _vbtodrupal_db_prefix_tables('{profile_values}', $drupal_db_prefix, $drupal_db_name),
422 VBTODRUPAL_ADD_TO_IDS,
423 _vbtodrupal_db_prefix_tables('{profile_fields}', $drupal_db_prefix, $drupal_db_name));
424
425 // Website address
426 $sql = 'INSERT IGNORE INTO %s (fid, uid, value) ';
427 $sql .= 'SELECT fid, userid+%d, homepage ';
428 $sql .= 'FROM {user}, %s ';
429 $sql .= 'WHERE name="user_website" AND homepage<>"";';
430 db_query($sql,
431 _vbtodrupal_db_prefix_tables('{profile_values}', $drupal_db_prefix, $drupal_db_name),
432 VBTODRUPAL_ADD_TO_IDS,
433 _vbtodrupal_db_prefix_tables('{profile_fields}', $drupal_db_prefix, $drupal_db_name));
434
435 // Location
436 $sql = 'INSERT IGNORE INTO %s (fid, uid, value) ';
437 $sql .= 'SELECT fid, userid+%d, ';
438 $sql .= 'REPLACE(REPLACE(REPLACE(REPLACE(field2, \'&amp;\', \'&\'), \'&quot;\', \'"\'), \'&lt;\', \'<\'), \'&gt;\', \'>\') ';
439 $sql .= 'FROM {userfield}, %s ';
440 $sql .= 'WHERE name="user_from" AND field2<>"";';
441 db_query($sql,
442 _vbtodrupal_db_prefix_tables('{profile_values}', $drupal_db_prefix, $drupal_db_name),
443 VBTODRUPAL_ADD_TO_IDS,
444 _vbtodrupal_db_prefix_tables('{profile_fields}', $drupal_db_prefix, $drupal_db_name));
445
446 // Occupation
447 $sql = 'INSERT IGNORE INTO %s (fid, uid, value) ';
448 $sql .= 'SELECT fid, userid+%d, ';
449 $sql .= 'REPLACE(REPLACE(REPLACE(REPLACE(field4, \'&amp;\', \'&\'), \'&quot;\', \'"\'), \'&lt;\', \'<\'), \'&gt;\', \'>\') ';
450 $sql .= 'FROM {userfield}, %s ';
451 $sql .= 'WHERE name="user_occ" AND field4<>"";';
452 db_query($sql,
453 _vbtodrupal_db_prefix_tables('{profile_values}', $drupal_db_prefix, $drupal_db_name),
454 VBTODRUPAL_ADD_TO_IDS,
455 _vbtodrupal_db_prefix_tables('{profile_fields}', $drupal_db_prefix, $drupal_db_name));
456
457 // Interests
458 $sql = 'INSERT IGNORE INTO %s (fid, uid, value) ';
459 $sql .= 'SELECT fid, userid+%d, ';
460 $sql .= 'REPLACE(REPLACE(REPLACE(REPLACE(field3, \'&amp;\', \'&\'), \'&quot;\', \'"\'), \'&lt;\', \'<\'), \'&gt;\', \'>\') ';
461 $sql .= 'FROM {userfield}, %s ';
462 $sql .= 'WHERE name="user_interests" AND field3<>"";';
463 db_query($sql,
464 _vbtodrupal_db_prefix_tables('{profile_values}', $drupal_db_prefix, $drupal_db_name),
465 VBTODRUPAL_ADD_TO_IDS,
466 _vbtodrupal_db_prefix_tables('{profile_fields}', $drupal_db_prefix, $drupal_db_name));
467
468 // Gender
469 $sql = 'INSERT IGNORE INTO %s (fid, uid, value) ';
470 $sql .= 'SELECT fid, userid+%d, field5 ';
471 $sql .= 'FROM {userfield}, %s ';
472 $sql .= 'WHERE name="user_gender" AND (field5="Male" OR field5="Female");';
473 db_query($sql,
474 _vbtodrupal_db_prefix_tables('{profile_values}', $drupal_db_prefix, $drupal_db_name),
475 VBTODRUPAL_ADD_TO_IDS,
476 _vbtodrupal_db_prefix_tables('{profile_fields}', $drupal_db_prefix, $drupal_db_name));
477
478 // Roles
479 $sql = 'INSERT IGNORE INTO %s (rid, name) ';
480 $sql .= 'SELECT usergroupid+%d, title ';
481 $sql .= 'FROM {usergroup};';
482 db_query($sql,
483 _vbtodrupal_db_prefix_tables('{role}', $drupal_db_prefix, $drupal_db_name),
484 VBTODRUPAL_ADD_TO_IDS);
485
486 // User roles (match the users to their roles)
487 $sql = 'INSERT IGNORE INTO %s (uid, rid) ';
488 $sql .= 'SELECT userid+%d, usergroupid+%d ';
489 $sql .= 'FROM {user}';
490 db_query($sql,
491 _vbtodrupal_db_prefix_tables('{users_roles}', $drupal_db_prefix, $drupal_db_name),
492 VBTODRUPAL_ADD_TO_IDS,
493 VBTODRUPAL_ADD_TO_IDS);
494
495 $sql = 'SELECT usergroupid FROM {usergroup};';
496 $user_group_query = db_query($sql);
497
498 // Each user may be a member of every role, so loop through each
499 // user_groupid, inserting user_role records for each user found
500 while ($user_group = db_fetch_object($user_group_query)) {
501 $sql = 'INSERT IGNORE INTO %s (uid, rid) ';
502 $sql .= 'SELECT userid+%d, %d+%d ';
503 $sql .= 'FROM {user} ';
504 $sql .= 'WHERE FIND_IN_SET(%d, membergroupids)<>0;';
505 db_query($sql,
506 _vbtodrupal_db_prefix_tables('{users_roles}', $drupal_db_prefix, $drupal_db_name),
507 VBTODRUPAL_ADD_TO_IDS,
508 $user_group->usergroupid,
509 VBTODRUPAL_ADD_TO_IDS,
510 $user_group->usergroupid);
511 }
512
513 _vbtodrupal_db_restore();
514 }
515
516 /**
517 * Helper function that does the donkey work of
518 * migrating forums to containers/forums
519 */
520 function _vbtodrupal_convforums() {
521 $drupal_settings = _vbtodrupal_db_setup();
522 $drupal_db_name = $drupal_settings['drupal_db_name'];
523 $drupal_db_prefix = $drupal_settings['drupal_db_prefix'];
524
525 // Grab the vid for the Forums vocabulary. Will need when
526 // inserting into other taxonomy tables
527 $sql = 'SELECT vid FROM %s WHERE module="forum";';
528 $forum_vid = db_fetch_object(db_query($sql,
529 _vbtodrupal_db_prefix_tables('{vocabulary}', $drupal_db_prefix, $drupal_db_name)));
530
531 // Forums
532 $sql = 'INSERT IGNORE INTO %s (tid, vid, name, description, weight) ';
533 $sql .= 'SELECT forumid+%d, %s, title, description, displayorder ';
534 $sql .= 'FROM {forum};';
535 db_query($sql,
536 _vbtodrupal_db_prefix_tables('{term_data}', $drupal_db_prefix, $drupal_db_name),
537 VBTODRUPAL_ADD_TO_IDS,
538 $forum_vid->vid);
539
540 // Forum hierachy - Top level containers
541 $sql = 'INSERT IGNORE INTO %s (tid, parent) ';
542 $sql .= 'SELECT forumid+%d, 0 ';
543 $sql .= 'FROM {forum} ';
544 $sql .= 'WHERE parentid=(-1);';
545 db_query($sql,
546 _vbtodrupal_db_prefix_tables('{term_hierarchy}', $drupal_db_prefix, $drupal_db_name),
547 VBTODRUPAL_ADD_TO_IDS);
548
549 // Forum hierachy - Rest of the hierarchy
550 $sql = 'INSERT IGNORE INTO %s (tid, parent) ';
551 $sql .= 'SELECT forumid+%d, parentid+%d ';
552 $sql .= 'FROM {forum} ';
553 $sql .= 'WHERE parentid>(-1);';
554 db_query($sql,
555 _vbtodrupal_db_prefix_tables('{term_hierarchy}', $drupal_db_prefix, $drupal_db_name),
556 VBTODRUPAL_ADD_TO_IDS,
557 VBTODRUPAL_ADD_TO_IDS);
558
559 // Build containers array and save
560 $containers = variable_get('forum_containers', array());
561 $sql = 'SELECT forumid+%d AS forumid FROM {forum} WHERE parentid=(-1)';
562 $containers_query = db_query($sql, VBTODRUPAL_ADD_TO_IDS);
563 while ($db_containers = db_fetch_object($containers_query)) {
564 if (!in_array($db_containers->forumid, $containers)) {
565 $containers[] = $db_containers->forumid;
566 }
567 }
568
569 _vbtodrupal_db_restore();
570 variable_set('forum_containers', $containers);
571 }
572
573 /**
574 * Helper function that does the donkey work of
575 * migrating threads
576 */
577 function _vbtodrupal_convthreads() {
578 $drupal_settings = _vbtodrupal_db_setup();
579 $drupal_db_name = $drupal_settings['drupal_db_name'];
580 $drupal_db_prefix = $drupal_settings['drupal_db_prefix'];
581
582 // Import threads as Drupal nodes
583 $sql = 'INSERT IGNORE INTO %s (nid, vid, type, title, uid, status, created, comment, sticky) ';
584 $sql .= 'SELECT threadid+%d, threadid+%d, \'forum\', ';
585 $sql .= ' REPLACE(REPLACE(REPLACE(REPLACE(title, \'&amp;\', \'&\'), \'&quot;\', \'"\'), \'&lt;\', \'<\'), \'&gt;\', \'>\'), ';
586 // post/userid==1 is a deleted user
587 $sql .= ' IF(postuserid=0,0,postuserid+%d), ';
588 $sql .= ' IF(visible=1,1,0), dateline, '; // status and created
589 // open: 1=read/write 0=locked 10=moderated (posts deleted etc.)
590 $sql .= ' IF(open=1, %d, %d), ';
591 $sql .= ' sticky ';
592 $sql .= 'FROM {thread} ';
593 // We don't import poll threads at this point
594 $sql .= 'WHERE pollid=0;';
595 db_query($sql,
596 _vbtodrupal_db_prefix_tables('{node}', $drupal_db_prefix, $drupal_db_name),
597 VBTODRUPAL_ADD_TO_IDS,
598 VBTODRUPAL_ADD_TO_IDS,
599 VBTODRUPAL_ADD_TO_IDS,
600 COMMENT_NODE_READ_WRITE,
601 COMMENT_NODE_READ_ONLY);
602
603 // Hook nodes up to taxonomy terms (forums)
604 $sql = 'INSERT IGNORE INTO %s (nid, tid) ';
605 $sql .= 'SELECT threadid+%d, forumid+%d ';
606 $sql .= 'FROM {thread};';
607 db_query($sql,
608 _vbtodrupal_db_prefix_tables('{term_node}', $drupal_db_prefix, $drupal_db_name),
609 VBTODRUPAL_ADD_TO_IDS,
610 VBTODRUPAL_ADD_TO_IDS);
611
612 // Fill in Forum table: not sure what this does
613 // that term_node doesn't
614 $sql = 'INSERT IGNORE INTO %s (nid, vid, tid) ';
615 $sql .= 'SELECT threadid+%d, threadid+%d, forumid+%d ';
616 $sql .= 'FROM {thread};';
617 db_query($sql,
618 _vbtodrupal_db_prefix_tables('{forum}', $drupal_db_prefix, $drupal_db_name),
619 VBTODRUPAL_ADD_TO_IDS,
620 VBTODRUPAL_ADD_TO_IDS,
621 VBTODRUPAL_ADD_TO_IDS);
622
623 // Nodes text
624 $sql = 'INSERT IGNORE INTO %s (nid, vid, uid, title, body, teaser, log, timestamp, format) ';
625 $sql .= 'SELECT {thread}.threadid+%d, {thread}.threadid+%d, IF(userid=0,0,userid+%d), ';
626 $sql .= ' REPLACE(REPLACE(REPLACE(REPLACE({thread}.title, \'&amp;\', \'&\'), \'&quot;\', \'"\'), \'&lt;\', \'<\'), \'&gt;\', \'>\'), ';
627 $sql .= ' pagetext, LEFT(pagetext, 250) AS teaser, notes, {thread}.dateline, 1 ';
628 $sql .= 'FROM {thread} INNER JOIN post ON {thread}.firstpostid={post}.postid ';
629 //$sql .= 'WHERE {thread}.visible = 1 AND {post}.visible = 1;';
630 db_query($sql,
631 _vbtodrupal_db_prefix_tables('{node_revisions}', $drupal_db_prefix, $drupal_db_name),
632 VBTODRUPAL_ADD_TO_IDS,
633 VBTODRUPAL_ADD_TO_IDS,
634 VBTODRUPAL_ADD_TO_IDS);
635
636 _vbtodrupal_db_restore();
637 }
638
639 /**
640 * Helper function that does the donkey work of
641 * migrating posts into Drupal comments
642 */
643 function _vbtodrupal_convposts() {
644 $drupal_settings = _vbtodrupal_db_setup();
645 $drupal_db_name = $drupal_settings['drupal_db_name'];
646 $drupal_db_prefix = $drupal_settings['drupal_db_prefix'];
647
648 // Import comments
649 $sql = 'INSERT IGNORE INTO %s (cid, pid, nid, uid, subject, comment, hostname, timestamp, status, format, users, name, mail, homepage) ';
650 $sql .= 'SELECT postid+%d, parentid+%d, threadid+%d, IF({post}.userid=0,0,{post}.userid+%d), ';
651 $sql .= ' REPLACE(REPLACE(REPLACE(REPLACE(title, \'&amp;\', \'&\'), \'&quot;\', \'"\'), \'&lt;\', \'<\'), \'&gt;\', \'>\'), ';
652 $sql .= ' pagetext, {post}.ipaddress, dateline, IF(visible=1,%d,%d), 1, \'%s\', {user}.username, email, homepage ';
653 $sql .= 'FROM {post} LEFT OUTER JOIN {user} ON {post}.userid={user}.userid ';
654 db_query($sql,
655 _vbtodrupal_db_prefix_tables('{comments}', $drupal_db_prefix, $drupal_db_name),
656 VBTODRUPAL_ADD_TO_IDS,
657 VBTODRUPAL_ADD_TO_IDS,
658 VBTODRUPAL_ADD_TO_IDS,
659 VBTODRUPAL_ADD_TO_IDS,
660 COMMENT_PUBLISHED,
661 COMMENT_NOT_PUBLISHED,
662 serialize(array(0 => 1)));
663
664 /**
665 * Comments to delete as they are already in the topic node. This would
666 * be achieved with a simple non-correlated (note: non) but for a
667 * bug in MySQL. See: http://bugs.mysql.com/bug.php?id=9090
668 * So we do data lifting in the application layer: annoying.
669 */
670 $sql = 'SELECT firstpostid+%d AS cid FROM {thread};';
671 $comments_query = db_query($sql, VBTODRUPAL_ADD_TO_IDS);
672 // Loop through dataset, generating array of firstpostids
673 while ($comments_query_row = db_fetch_object($comments_query)) {
674 $comments_to_delete[] = $comments_query_row->cid;
675 }
676 // implode firstpostids into comma seperated list for MySQL
677 $sql = 'DELETE FROM %s WHERE cid IN (%s);';
678 db_query($sql,
679 _vbtodrupal_db_prefix_tables('{comments}', $drupal_db_prefix, $drupal_db_name),
680 implode(',',$comments_to_delete));
681
682 // Rebuild thread column, any optimisations to this code would be welcome
683 // this is the slowest part of the migration, and it is SLOW
684 $sql = 'SELECT cid, pid, nid, thread ';
685 $sql .= 'FROM %s ';
686 $sql .= 'WHERE thread="" ';
687 $sql .= 'ORDER BY timestamp;';
688 $thread_query = db_query($sql,
689 _vbtodrupal_db_prefix_tables('{comments}', $drupal_db_prefix, $drupal_db_name));
690
691 while ($empty_threads = db_fetch_object($thread_query)) {
692 if ($empty_threads->pid == 0) {
693 // No parent
694 $max = db_result(db_query('SELECT MAX(thread) FROM %s WHERE nid = %d',
695 _vbtodrupal_db_prefix_tables('{comments}', $drupal_db_prefix, $drupal_db_name),
696 $empty_threads->nid));
697
698 if ($max == '') {
699 $thread = int2vancode(1) . '/';
700 }
701 else {
702 // Strip the "/" from the end of the thread.
703 $max = rtrim($max, '/');
704 $thread = int2vancode(vancode2int($max)+1) . '/';
705 }
706 }
707 else {
708 // Has a parent
709
710 // Get the parent comment:
711 $parent = db_fetch_object(db_query('SELECT * FROM %s WHERE cid = %d',
712 _vbtodrupal_db_prefix_tables('{comments}', $drupal_db_prefix, $drupal_db_name),
713 $empty_threads->pid));
714
715 // Strip the "/" from the end of the parent thread.
716 $parent->thread = (string) rtrim((string) $parent->thread, '/');
717
718 // Get the max value in _this_ thread.
719 $max = db_result(db_query("SELECT MAX(thread) FROM %s WHERE thread LIKE '%s.%%' AND nid = %d",
720 _vbtodrupal_db_prefix_tables('{comments}', $drupal_db_prefix, $drupal_db_name),
721 $parent->thread,
722 $empty_threads->nid));
723
724 if ($max == '') {
725 // First child of this parent.
726 $thread = $parent->thread .'.'.int2vancode(1).'/';
727 }
728 else {
729 // Strip the "/" at the end of the thread.
730 $max = rtrim($max, '/');
731
732 // We need to get the value at the correct depth.
733 $parts = explode('.', $max);
734 $parent_depth = count(explode('.', $parent->thread));
735 $last = $parts[$parent_depth];
736
737 // Finally, build the thread field for this new comment.
738 $thread = $parent->thread .'.'. int2vancode(vancode2int($last) + 1) .'/';
739 }
740 }
741 // Update the value in the db
742 $sql = 'UPDATE %s SET thread = \'%s\' WHERE cid = %d';
743 db_query($sql,
744 _vbtodrupal_db_prefix_tables('{comments}', $drupal_db_prefix, $drupal_db_name),
745 $thread,
746 $empty_threads->cid);
747 }
748
749 _vbtodrupal_db_restore();
750 }
751
752 /**
753 * Function to do the donkey work of
754 * migrating polls.
755 *
756 */
757 function _vbtodrupal_convpolls() {
758 $drupal_settings = _vbtodrupal_db_setup();
759 $drupal_db_name = $drupal_settings['drupal_db_name'];
760 $drupal_db_prefix = $drupal_settings['drupal_db_prefix'];
761
762 // Polls table, not much info in here...
763 // By default we flag all polls as 'active'
764 $sql = 'INSERT IGNORE INTO %s (nid, runtime, active) ';
765 $sql .= 'SELECT threadid+%d, timeout, active ';
766 $sql .= 'FROM {poll} INNER JOIN {thread} ON {poll}.pollid={thread}.pollid ';
767 db_query($sql,
768 _vbtodrupal_db_prefix_tables('{poll}', $drupal_db_prefix, $drupal_db_name),
769 VBTODRUPAL_ADD_TO_IDS);
770
771 // Poll node item
772 $sql = 'INSERT IGNORE INTO %s (nid, vid, type, title, uid, status, created, comment, sticky) ';
773 $sql .= 'SELECT {thread}.threadid+%d, {thread}.threadid+%d, \'poll\', ';
774 $sql .= ' REPLACE(REPLACE(REPLACE(REPLACE(question, \'&amp;\', \'&\'), \'&quot;\', \'"\'), \'&lt;\', \'<\'), \'&gt;\', \'>\'), ';
775 $sql .= ' IF(postuserid=0,0,postuserid+%d), IF(visible=1,1,0), {poll}.dateline, ';
776 $sql .= 'IF(open=1, %d, %d), sticky ';
777 $sql .= 'FROM {poll} INNER JOIN {thread} ON {poll}.pollid={thread}.pollid ';
778 db_query($sql,
779 _vbtodrupal_db_prefix_tables('{node}', $drupal_db_prefix, $drupal_db_name),
780 VBTODRUPAL_ADD_TO_IDS,
781 VBTODRUPAL_ADD_TO_IDS,
782 VBTODRUPAL_ADD_TO_IDS,
783 COMMENT_NODE_READ_WRITE,
784 COMMENT_NODE_READ_ONLY);
785
786 $sql = 'SELECT {poll}.pollid, threadid, {poll}.options ';
787 $sql .= 'FROM {poll} INNER JOIN {thread} ON {poll}.pollid={thread}.pollid ';
788 $poll_query = db_query($sql);
789 $primary_key_num = 0;
790
791 while ($poll_query_item = db_fetch_object($poll_query)) {
792 $sql = 'INSERT IGNORE INTO %s (chid, nid, chtext, chvotes, chorder) VALUES ';
793 $poll_options = explode('|||', $poll_query_item->options);
794 for ($poll_option_num = 0; $poll_option_num < count($poll_options); $poll_option_num++) {
795 $primary_key_num++;
796 // Insert comma between value sets
797 if ($poll_option_num > 0) {
798 $sql .= ',';
799 }
800 $sql .= '( ';
801 $sql .= (int) $primary_key_num .'+'. (int) VBTODRUPAL_ADD_TO_IDS .', ';
802 $sql .= (int) $poll_query_item->threadid .'+'. (int) VBTODRUPAL_ADD_TO_IDS .', ';
803 $sql .= "'". db_escape_string($poll_options[$poll_option_num]) ."'" .' , ';
804 $sql .= '0, '. (int) $poll_option_num;
805 $sql .= ' )';
806 }
807 db_query($sql,
808 _vbtodrupal_db_prefix_tables('{poll_choices}',
809 $drupal_db_prefix,
810 $drupal_db_name));
811 }
812
813 // Poll votes
814 $sql = 'INSERT IGNORE INTO %s (nid, uid, chorder) ';
815 $sql .= 'SELECT threadid+%d, IF(userid=0,0,userid+%d), voteoption-1 ';
816 $sql .= 'FROM {pollvote} INNER JOIN {thread} ON {pollvote}.pollid={thread}.pollid ';
817 db_query($sql,
818 _vbtodrupal_db_prefix_tables('{poll_votes}', $drupal_db_prefix, $drupal_db_name),
819 VBTODRUPAL_ADD_TO_IDS,
820 VBTODRUPAL_ADD_TO_IDS);
821
822 // Update vote statistics (this is easier than
823 // trying to extract badly stored values from vBulletin!)
824 $sql = 'UPDATE %s AS pc ';
825 $sql .= 'SET chvotes=( ';
826 $sql .= 'SELECT COUNT(*) ';
827 $sql .= ' FROM %s ';
828 $sql .= ' WHERE %s.nid=pc.nid ';
829 $sql .= ' AND %s.chorder=pc.chorder ';
830 $sql .= ' )';
831 db_query($sql,
832 _vbtodrupal_db_prefix_tables('{poll_choices}', $drupal_db_prefix, $drupal_db_name),
833 _vbtodrupal_db_prefix_tables('{poll_votes}', $drupal_db_prefix, $drupal_db_name),
834 _vbtodrupal_db_prefix_tables('{poll_votes}', $drupal_db_prefix, $drupal_db_name),
835 _vbtodrupal_db_prefix_tables('{poll_votes}', $drupal_db_prefix, $drupal_db_name));
836
837 _vbtodrupal_db_restore();
838
839 // Now we have the Drupal db selected...
840 // Run poll_cron to close polls that are no longer active
841 poll_cron();
842 }
843
844 /**
845 * Function to do the donkey work of
846 * migrating files.
847 *
848 */
849 function _vbtodrupal_convfiles() {
850 $file_path = variable_get('file_directory_path', 'files');
851 $picture_path = variable_get('user_picture_path', 'pictures');
852 $drupal_settings = _vbtodrupal_db_setup();
853 $drupal_db_name = $drupal_settings['drupal_db_name'];
854 $drupal_db_prefix = $drupal_settings['drupal_db_prefix'];
855
856 /**
857 * Attachments in vB are attached to posts, but in Drupal we have deleted
858 * posts which are first in topic. So we link attachment to thread by
859 * firstpostid to find the Drupal node id the file should be attached to.
860 * The comment attachments will be dealt with shortly.
861 */
862 $sql = 'INSERT IGNORE INTO %s (fid, nid, filename, filepath, filemime, filesize) ';
863 // When file attachments are imported from the vB database the filename is prepended with the attachmentid to prevent duplicate file names
864 $sql .= 'SELECT attachmentid+%d, threadid+%d, CONCAT((attachmentid+%d), \'_\', filename), CONCAT(\'%s\', (attachmentid+%d), \'_\', filename), ';
865 // H4Xx0r serialised data to get the MIME type (sorry for those, including myself, who have
866 // to understand this in the future). Try using MySQL Query Browser to debug. :)
867 $sql .= 'TRIM(LEFT(MID(mimetype, LOCATE(\'Content-type:\', mimetype)+LENGTH(\'Content-type:\'), LENGTH(mimetype)), LOCATE(\'"\',MID(mimetype, LOCATE(\'Content-type:\', mimetype)+LENGTH(\'Content-type:\'), LENGTH(mimetype)))-1)), ';
868 $sql .= 'filesize ';
869 $sql .= 'FROM {attachment} ';
870 $sql .= ' INNER JOIN {thread} ON {attachment}.postid={thread}.firstpostid ';
871 $sql .= ' INNER JOIN {attachmenttype} ON {attachment}.extension={attachmenttype}.extension;';
872 db_query($sql,
873 _vbtodrupal_db_prefix_tables('{files}', $drupal_db_prefix, $drupal_db_name),
874 VBTODRUPAL_ADD_TO_IDS,
875 VBTODRUPAL_ADD_TO_IDS,
876 VBTODRUPAL_ADD_TO_IDS,
877 $file_path ."/",
878 VBTODRUPAL_ADD_TO_IDS);
879
880 // Populate file_revisions table
881 $sql = 'INSERT IGNORE INTO %s (fid, vid, description, list) ';
882 $sql .= 'SELECT attachmentid+%d, threadid+%d, filename, {attachment}.visible ';
883 $sql .= 'FROM {attachment} ';
884 $sql .= ' INNER JOIN {thread} ON {attachment}.postid={thread}.firstpostid ';
885 db_query($sql,
886 _vbtodrupal_db_prefix_tables('{file_revisions}', $drupal_db_prefix, $drupal_db_name),
887 VBTODRUPAL_ADD_TO_IDS,
888 VBTODRUPAL_ADD_TO_IDS);
889
890 // Now we work through attachments on posts (comments)
891 $sql = 'INSERT IGNORE INTO %s (fid, nid, cid, filename, filepath, filemime, filesize, description, list) ';
892 $sql .= 'SELECT attachmentid+%d, threadid+%d, {post}.postid+%d, CONCAT((attachmentid+%d), \'_\', filename), CONCAT(\'%s\', (attachmentid+%d), \'_\', filename), ';
893 $sql .= 'TRIM(LEFT(MID(mimetype, LOCATE(\'Content-type:\', mimetype)+LENGTH(\'Content-type:\'), LENGTH(mimetype)), LOCATE(\'"\',MID(mimetype, LOCATE(\'Content-type:\', mimetype)+LENGTH(\'Content-type:\'), LENGTH(mimetype)))-1)), ';
894 $sql .= 'filesize, filename, {attachment}.visible ';
895 $sql .= 'FROM {attachment} ';
896 $sql .= ' INNER JOIN {post} ON {attachment}.postid={post}.postid ';
897 $sql .= ' INNER JOIN {attachmenttype} ON {attachment}.extension={attachmenttype}.extension;';
898 db_query($sql,
899 _vbtodrupal_db_prefix_tables('{comment_upload_files}', $drupal_db_prefix, $drupal_db_name),
900 VBTODRUPAL_ADD_TO_IDS,
901 VBTODRUPAL_ADD_TO_IDS,
902 VBTODRUPAL_ADD_TO_IDS,
903 VBTODRUPAL_ADD_TO_IDS,
904 $file_path ."/",
905 VBTODRUPAL_ADD_TO_IDS);
906
907 // Now the attachments/avatars must be taken from the database and saved to disk
908 $sql = 'SELECT attachmentid+%d AS uniqueid, filename, filedata, 0 AS avatar ';
909 $sql .= 'FROM {attachment} ';
910 $sql .= 'UNION SELECT IF(userid=0,0,userid+%d) AS uniqueid, filename, filedata, 1 AS avatar ';
911 $sql .= 'FROM {customavatar};';
912 $attachment_query = db_query($sql,
913 VBTODRUPAL_ADD_TO_IDS,
914 VBTODRUPAL_ADD_TO_IDS);
915
916 // Cycle through all blobs in the query
917 while ($attachment_query_item = db_fetch_object($attachment_query)) {
918 if ($attachment_query_item->avatar == 0) {
919 $filename = $file_path;
920 }
921 else {
922 $filename = $file_path .'/'. $picture_path;
923 }
924 // Add filename, prepend userid/attachmentid so there are no duplicate files
925 $filename .= '/'. $attachment_query_item->uniqueid .'_'. $attachment_query_item->filename;
926 file_save_data($attachment_query_item->filedata, $filename, FILE_EXISTS_REPLACE);
927 }
928
929 _vbtodrupal_db_restore();
930 }
931
932 /**
933 * Function to do the donkey work of
934 * migrating private messages.
935 * TODO: Make this work with multiple recipients
936 *
937 */
938 function _vbtodrupal_convpms() {
939 $drupal_settings = _vbtodrupal_db_setup();
940 $drupal_db_name = $drupal_settings['drupal_db_name'];
941 $drupal_db_prefix = $drupal_settings['drupal_db_prefix'];
942
943 // Note we set the folder ID to 0 here. Set everything to Inbox, then UPDATE later on,
944 // this ensures no messages are left without a folder (since we can't import subfolders)
945 $sql = 'INSERT IGNORE INTO %s (id, author, recipient, subject, message, timestamp, newmsg, folder, author_del, recipient_del, format) ';
946 $sql .= 'SELECT {pm}.pmid+%d, IF(fromuserid=0,0,fromuserid+%d), IF(userid=0,0,userid+%d), ';
947 $sql .= ' REPLACE(REPLACE(REPLACE(REPLACE(title, \'&amp;\', \'&\'), \'&quot;\', \'"\'), \'&lt;\', \'<\'), \'&gt;\', \'>\'), ';
948 $sql .= ' message, dateline, IF(messageread<>0,0,1), ';
949 $sql .= ' IF(folderid>0, CONCAT(IF(fromuserid=0,0,fromuserid+%d), folderid), 0), IF(folderid=0,1,0), IF(folderid=(-1),1,0), 1 ';
950 $sql .= 'FROM {pm} INNER JOIN {pmtext} ON {pm}.pmtextid={pmtext}.pmtextid;';
951 db_query($sql,
952 _vbtodrupal_db_prefix_tables('{privatemsg}', $drupal_db_prefix, $drupal_db_name),
953 VBTODRUPAL_ADD_TO_IDS,
954 VBTODRUPAL_ADD_TO_IDS,
955 VBTODRUPAL_ADD_TO_IDS,
956 VBTODRUPAL_ADD_TO_IDS);
957
958 // PM Folders: more questionable database design, all the folders are stored in
959 // usertextfield in a serialised array. More data lifting in the app layer.
960 $sql = 'SELECT IF(userid=0,0,userid+%d) AS userid, pmfolders FROM {usertextfield} WHERE pmfolders<>"";';
961 $pmfolder_query = db_query($sql, VBTODRUPAL_ADD_TO_IDS);
962 while ($pmfolder_query_item = db_fetch_object($pmfolder_query)) {
963 $pmfolder_data = unserialize($pmfolder_query_item->pmfolders);
964 $sql = 'INSERT IGNORE INTO %s (fid, uid, name) VALUES ';
965 for ($pmfolder_count = 0; $pmfolder_count < count($pmfolder_data); $pmfolder_count++) {
966 $pmfolder_details = each($pmfolder_data);
967 // Weed out blank values
968 if ($pmfolder_details['value']) {
969 // Insert comma between value sets
970 if ($pmfolder_count > 0) {
971 $sql .= ',';
972 }
973 $unique_id = ($pmfolder_query_item->userid == 0 ? 0 : $pmfolder_query_item->userid) . $pmfolder_details['key'];
974 $sql .= '( ';
975 $sql .= (int) $unique_id .', ';
976 $sql .= (int) ($pmfolder_query_item->userid == 0 ? 0 : $pmfolder_query_item->userid) .', ';
977 $sql .= '\''. db_escape_string($pmfolder_details['value']) .'\'';
978 $sql .= ') ';
979 }
980 }
981
982 db_query($sql,
983 _vbtodrupal_db_prefix_tables('{privatemsg_folder}', $drupal_db_prefix, $drupal_db_name));
984 }
985
986 _vbtodrupal_db_restore();
987 }
988
989 /**
990 * Helper function which updates thread statistics
991 */
992 function _vbtodrupal_updatestats() {
993 // Truncate stats table
994 $sql = 'TRUNCATE TABLE {node_comment_statistics}';
995 db_query($sql);
996
997 $sql = 'INSERT INTO {node_comment_statistics} (nid, last_comment_timestamp, last_comment_uid, comment_count) ';
998 $sql .= 'SELECT nid, ';
999 $sql .= '(SELECT MAX(timestamp) FROM {comments} WHERE {comments}.nid = n.nid), ';
1000 $sql .= '(SELECT uid FROM {comments} WHERE {comments}.nid = n.nid ORDER BY timestamp DESC LIMIT 1), ';
1001 $sql .= '(SELECT COUNT(*) FROM {comments} WHERE {comments}.nid = n.nid) ';
1002 $sql .= 'FROM {node} AS n';
1003 db_query($sql);
1004 }
1005
1006 /**
1007 * Helper function that makes vBulletin's different
1008 * BBCode implementation work with the BBCode module
1009 */
1010 function _vbtodrupal_fixbbcode() {
1011
1012 // Nodes
1013 // Find any nodes that have BBcode with speech marks in them
1014 // Shame that MySQL regex can only be used for matching not updates
1015 $sql = 'SELECT nid, body ';
1016 $sql .= 'FROM {node_revisions} ';
1017 $sql .= 'WHERE body REGEXP \'\\[[[:alnum:]]+="[[:alnum:][:punct:]]+"\\]\';';
1018 $bbnode_query = db_query($sql);
1019 while($bbnode_item = db_fetch_object($bbnode_query)) {
1020 $sql = ' UPDATE {node_revisions} SET body=\'%s\' ';
1021 $sql .= 'WHERE nid=%d;';
1022 // Scoops out everything from the BBCode except speech mark characters
1023 db_query($sql, preg_replace('#(\[\w+=)"([\w:;&,%+~!=@\/\.\-\#\?\(\)]+)"(\])#si', '$1$2$3', $bbnode_item->body), $bbnode_item->nid);
1024 }
1025
1026 // Comments
1027 $sql = 'SELECT cid, comment ';
1028 $sql .= 'FROM {comments} ';
1029 $sql .= 'WHERE comment REGEXP \'\\[[[:alnum:]]+="[[:alnum:][:punct:]]+"\\]\';';
1030 $bbcomment_query = db_query($sql);
1031 while($bbcomment_item = db_fetch_object($bbcomment_query)) {
1032 $sql = ' UPDATE {comments} SET comment=\'%s\' ';
1033 $sql .= 'WHERE cid=%d;';
1034 // Scoops out everything from the BBCode except speech mark characters
1035 db_query($sql, preg_replace('#(\[\w+=)"([\w:;&,%+~!=@\/\.\-\#\?\(\)]+)"(\])#si', '$1$2$3', $bbcomment_item->comment), $bbcomment_item->cid);
1036 }
1037
1038 // Signatures
1039 $sql = 'SELECT uid, signature ';
1040 $sql .= 'FROM {users} ';
1041 $sql .= 'WHERE signature REGEXP \'\\[[[:alnum:]]+="[[:alnum:][:punct:]]+"\\]\';';
1042 $bbsig_query = db_query($sql);
1043 while($bbsig_item = db_fetch_object($bbsig_query)) {
1044 $sql = ' UPDATE {users} SET signature=\'%s\' ';
1045 $sql .= 'WHERE uid=%d;';
1046 // Scoops out everything from the BBCode except speech mark characters
1047 db_query($sql, preg_replace('#(\[\w+=)"([\w:;&,%+~!=@\/\.\-\#\?\(\)]+)"(\])#si', '$1$2$3', $bbsig_item->signature), $bbsig_item->uid);
1048 }
1049 }

  ViewVC Help
Powered by ViewVC 1.1.2