<?php
|
|
|
|
// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
|
|
//
|
|
// All Rights Reserved. See copyright.txt for details and a complete list of authors.
|
|
// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
|
|
// $Id$
|
|
|
|
// This script may only be included! Die if called directly...
|
|
if (strpos($_SERVER['SCRIPT_NAME'], basename(__FILE__)) !== false) {
|
|
header('location: index.php');
|
|
exit;
|
|
}
|
|
|
|
//comments lib and Comments class needed for use by tiki-forum_import.php
|
|
require_once('lib/comments/commentslib.php');
|
|
|
|
/**
|
|
* Importer
|
|
* A library to handle importing of forum posts from Tiki or from other forum
|
|
* software. This library will re-use functions contained in the CommentsLib
|
|
* library, as those functions already directly access the forums.
|
|
*
|
|
* @uses Comments
|
|
* @license LGPL. Please, see licence.txt for mode details
|
|
*/
|
|
class Importer extends Comments
|
|
{
|
|
// The types of forums are hard-coded into the library and displayed
|
|
// in the template. As support for more imports grows, add the type to
|
|
// the below two arrays, in addition to writing the functions to
|
|
// support them.
|
|
public $fi_types = ['TikiWiki'];
|
|
public $fi_prefixes = ['tiki_'];
|
|
|
|
|
|
/*
|
|
* Functions for the forums
|
|
*
|
|
* All functions that begin with "parse" are related to SQL file interaction.
|
|
* Functions that begin with "get" are related to DB interactions.
|
|
*
|
|
*/
|
|
|
|
/**
|
|
* importSQLForum importSQLForum will import the forum data from the specified SQL file and
|
|
* the specified forum ID, and append it to the end of the data in the
|
|
* destination forum. Datestamps will be retained.
|
|
*
|
|
* @param string $dbType
|
|
* @param string $dbPrefix
|
|
* @param string $sqlFile
|
|
* @param string $fF SQL file
|
|
* @param mixed $tF
|
|
* @access public
|
|
* @return int number of posts
|
|
*/
|
|
public function importSQLForum($dbType, $dbPrefix, $sqlFile, $fF, $tF)
|
|
{
|
|
$fHash = [];
|
|
$row = [];
|
|
$hash = []; // If part of a thread, this is the new parent threadId.
|
|
|
|
// Select the table for the main forum information.
|
|
if ($dbType == 'TikiWiki') {
|
|
$table = 'comments';
|
|
$ftable = $dbPrefix . $table;
|
|
$ftable2 = $dbPrefix . 'forums';
|
|
} else {
|
|
return -1;
|
|
}
|
|
|
|
// Parse the SQL file and grab all posts for the source forum.
|
|
$fHash = $this->parseSQL($dbType, $dbPrefix, $table, $sqlFile, $fF);
|
|
$fPosts = count($fHash);
|
|
$fPosts2 = $fPosts;
|
|
|
|
// In order to accommodate out of order posts and still keep integrity
|
|
// with threads, if a record has a parent ID (meaning it is part of a
|
|
// thread), then when looping through the array, stick it on the end
|
|
// and continue with the next one.
|
|
for ($count = 0; $count < $fPosts2; $count++) {
|
|
$row = array_shift($fHash);
|
|
|
|
$pid = 0;
|
|
if ($row['parentId'] != 0 && ! $hash[$row['parentId']]) {
|
|
array_push($fHash, $row);
|
|
$fPosts2++;
|
|
continue;
|
|
} elseif ($row['parentId'] != 0) {
|
|
$pid = $hash[$row['parentId']];
|
|
}
|
|
|
|
if ($dbType == 'TikiWiki') {
|
|
$query = 'insert into
|
|
`tiki_comments` (`objectType`, `object`, `commentDate`,
|
|
`userName`, `title`, `data`, `votes`, `points`, `hash`,
|
|
`parentId`, `average`, `hits`, `type`, `summary`, `user_ip`,
|
|
`message_id`, `in_reply_to`)
|
|
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
|
|
|
|
$result = $this->query($query, [
|
|
'forum',
|
|
$tF,
|
|
$row["commentDate"],
|
|
$row["userName"],
|
|
$row["title"],
|
|
$row["data"],
|
|
(int) $row["votes"],
|
|
$row["points"],
|
|
$row["hash"],
|
|
$pid,
|
|
$row["average"],
|
|
(int) $row["hits"],
|
|
$row["type"],
|
|
$row["summary"],
|
|
$row["user_ip"],
|
|
$row["message_id"],
|
|
$row["in_reply_to"]
|
|
]);
|
|
|
|
$abbb = $this->getOne("SELECT LAST_INSERT_ID() from $ftable");
|
|
|
|
if (! $abbb) {
|
|
$abbb = $this->getOne("SELECT max(tableId) from $ftable");
|
|
}
|
|
$hash[$row['threadId']] = $abbb;
|
|
} else {
|
|
die("Only TikiWiki is supported at this time.\n");
|
|
}
|
|
}
|
|
// Update forum counters.
|
|
$query = "select count(*) from `tiki_comments` where `objectType` = 'forum' and `object` = ?";
|
|
$tComments = $this->getOne($query, [ (int) $tF ]);
|
|
|
|
$query = "select count(*) from `tiki_comments` where `objectType` = 'forum' and `object` = ? and `parentId` = 0";
|
|
$tThreads = $this->getOne($query, [ (int) $tF ]);
|
|
|
|
$query = 'update `tiki_forums` set `comments` = ?, `threads` = ? where `forumId` = ?';
|
|
$result = $this->query($query, [ (int) $tComments, (int) $tThreads, (int) $tF ]);
|
|
|
|
// Force an index refresh on comments table.
|
|
include_once('lib/search/refresh-functions.php');
|
|
refresh_index_forums();
|
|
refresh_index('comments');
|
|
|
|
return $fPosts;
|
|
}
|
|
|
|
|
|
/**
|
|
* parseFields will take an entire record, as parsed out from an SQL file,
|
|
* and pull out full fields (either text-based with '' or numeric). What is
|
|
* returned is an indexed array of the field data.
|
|
*
|
|
* @param string $record
|
|
* @access public
|
|
* @return array: indexed array of the field data
|
|
*/
|
|
public function parseFields($record)
|
|
{
|
|
$fields = [];
|
|
$moo = "\'";
|
|
|
|
while ($a = strpos($record, ',')) {
|
|
// If field is a string...
|
|
if (preg_match("/^'/", substr($record, 0, $a))) {
|
|
$offset = 1;
|
|
while ($b = strpos($record, "'", $offset)) {
|
|
// If close quote is not escaped
|
|
if (substr($record, $b - 1, 2) != $moo) {
|
|
$field = substr($record, 1, $b - 1);
|
|
$field = str_replace('\r\n', '%%%', $field);
|
|
$fields[] = $field;
|
|
$record = substr($record, $b + 2);
|
|
break;
|
|
} else {
|
|
$offset = $b + 1;
|
|
}
|
|
}
|
|
// Otherwise, it is numeric.
|
|
} else {
|
|
$field = substr($record, 0, $a);
|
|
if (strpos($field, 'NULL') !== false && strlen($field) == 4) {
|
|
$field = null;
|
|
}
|
|
array_push($fields, $field);
|
|
$record = substr($record, $a + 1);
|
|
}
|
|
}
|
|
array_push($fields, $record);
|
|
|
|
return $fields;
|
|
}
|
|
|
|
/**
|
|
* parseSQL parses the SQL source file, analysing the block of text
|
|
* for the specified table, pulling out field names, and all of the
|
|
* values from the associated insert actions. Returns an array of
|
|
* associative arrays for each record and the fields within the record.
|
|
*
|
|
* @param string $dbType
|
|
* @param string $dbPrefix prefix of database tables
|
|
* @param string $table table name to parse
|
|
* @param string $sqlFile output file name
|
|
* @param mixed $fId
|
|
* @access public
|
|
* @return array of associative arrays for each record and the fields within the records
|
|
*/
|
|
public function parseSQL($dbType, $dbPrefix, $table, $sqlFile, $fId)
|
|
{
|
|
|
|
$headings = [];
|
|
$rec = [];
|
|
$thash = [];
|
|
|
|
$fH = fopen($sqlFile, 'r');
|
|
|
|
$lookFor1 = "^CREATE TABLE `$dbPrefix" . "$table`";
|
|
$lookFor2 = "^INSERT INTO `$dbPrefix" . "$table`";
|
|
|
|
while ($fL = fgets($fH)) {
|
|
// If we find a create table block, parse the
|
|
// entire block.
|
|
if (preg_match('/' . $lookFor1 . '/', $fL)) {
|
|
$fL = fgets($fH);
|
|
while (preg_match('/^ `/', $fL)) {
|
|
$a = substr($fL, 3);
|
|
$b = strpos($a, '`');
|
|
$c = substr($a, 0, $b);
|
|
array_push($headings, $c);
|
|
$fL = fgets($fH);
|
|
}
|
|
}
|
|
|
|
// Now that we've parsed the create table block,
|
|
// look for the insert block.
|
|
if (preg_match('/' . $lookFor2 . '/', $fL)) {
|
|
while (preg_match('/' . $lookFor2 . '/', $fL)) {
|
|
$a = strpos($fL, '(');
|
|
$b = strpos($fL, ");\n");
|
|
$c = substr($fL, $a + 1, $b - $a - 1);
|
|
|
|
// Do a rudimentary parsing of what generally would be
|
|
// record boundaries, such that each element in $records
|
|
// represents an SQL record or row.
|
|
$records = preg_split('/\),\(/', $c);
|
|
|
|
if (count($records) < 1) {
|
|
$records[0] = $c;
|
|
}
|
|
|
|
//first row may have column names - get rid of these
|
|
if (strpos($records[0], ') VALUES (') !== false) {
|
|
$split = strpos($records[0], ') VALUES (');
|
|
$records[0] = substr($records[0], $split + 10);
|
|
}
|
|
|
|
for ($count = 0, $count_records = count($records); $count < $count_records; $count++) {
|
|
// Each proper record should begin with a numeric value
|
|
// (at least as far as the tables we will be using).
|
|
// Check the following record from the current one to see
|
|
// if it is a proper record. If it is not, then it is
|
|
// the continuation of the current one, so merge them into
|
|
// the next record, and skip the current one. Repeat
|
|
// checking the next record until both the current one
|
|
// and its follower are proper.
|
|
while (isset($records[$count + 1]) && ! preg_match('/^[0-9]/', $records[$count + 1])) {
|
|
$newrec = $records[$count] . '),(' . $records[$count + 1];
|
|
$count++;
|
|
$records[$count] = $newrec;
|
|
}
|
|
$fields = $this->parseFields($records[$count]);
|
|
// This only supports TikiWiki at this time. Any other
|
|
// value that manages to get through will simply parse
|
|
// all records without filter.
|
|
if ($dbType == 'TikiWiki') {
|
|
// Ignore records that come back that are not
|
|
// forum-related.
|
|
if ($fields[2] != 'forum' && $table == 'comments') {
|
|
// Do nothing... NEXT!
|
|
continue;
|
|
// If a source forum has been specified, ignore
|
|
// records that are not for that specific forum.
|
|
} elseif ($fId && $fields[1] != "$fId" && $table == 'comments') {
|
|
// Do nothing... NEXT!
|
|
continue;
|
|
} else {
|
|
for ($z = 0, $zcount_fields = count($fields); $z < $zcount_fields; $z++) {
|
|
$rec[$headings[$z]] = $fields[$z];
|
|
}
|
|
array_push($thash, $rec);
|
|
}
|
|
}
|
|
}
|
|
$fL = fgets($fH);
|
|
}
|
|
}
|
|
}
|
|
return $thash;
|
|
}
|
|
|
|
/**
|
|
* parseForumList Parses an SQL file and returns an array consisting of all
|
|
* the forum ID number and name pairs that exist in the SQL file.
|
|
*
|
|
* @param string $dbType
|
|
* @param string $dbPrefix
|
|
* @param string $sqlFile
|
|
* @access public
|
|
* @return -1 if error. Else an array with all the forum Id numbers and name pairs that exist in the SQL file.
|
|
*/
|
|
public function parseForumList($dbType, $dbPrefix, $sqlFile)
|
|
{
|
|
$tHash = [];
|
|
$fields = [];
|
|
$forum = [];
|
|
$forums = [];
|
|
|
|
// Select the table for the main forum information.
|
|
if ($dbType == 'TikiWiki') {
|
|
$table = 'forums';
|
|
} else {
|
|
return -1;
|
|
}
|
|
|
|
$tHash = $this->parseSQL($dbType, $dbPrefix, $table, $sqlFile, null);
|
|
|
|
// We only need to key on the forum ID number and the forum name.
|
|
while ($fields = array_shift($tHash)) {
|
|
if ($dbType == 'TikiWiki') {
|
|
$forum['id'] = $fields['forumId'];
|
|
$forum['name'] = $fields['name'];
|
|
$forum['comments'] = $fields['comments'];
|
|
array_push($forums, $forum);
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
return $forums;
|
|
}
|
|
}
|