, where NNN is the gedcom ID.
* It will then call import.php to load the div's contents using AJAX.
*
* We start importing at position wt_gedcom.import_offset and continue
* for a couple of seconds. When we've finished we set import_offset to
* zero to indicate success.
*
* webtrees: Web based Family History software
* Copyright (C) 2010 webtrees development team.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* @version $Id$
*/
define('WT_SCRIPT_NAME', 'import.php');
require './includes/session.php';
require_once WT_ROOT.'includes/functions/functions_import.php';
// Don't use ged=XX as we want to be able to run without changing the current gedcom.
// This will let us load several gedcoms together, or to edit one while loading another.
$gedcom_id=safe_GET('gedcom_id');
if (!userGedcomAdmin(WT_USER_ID, $gedcom_id)) {
header('HTTP/1.0 403 Forbidden');
exit;
}
// Don't allow the user to cancel the request. We do not want
// to be left with an incomplete transaction, as this could cause a
// timeout error in another session.
ignore_user_abort(true);
// Run in a transaction, and make sure we are the only ones importing this gedcom
WT_DB::exec("START TRANSACTION");
// What is the current import status?
$row=WT_DB::prepare(
"SELECT import_offset, LENGTH(import_gedcom) AS import_total FROM {$TBLPREFIX}gedcom WHERE gedcom_id=? FOR UPDATE"
)->execute(array($gedcom_id))->fetchOneRow();
if (!$row) {
// No such gedcom? Deleted in another session? die quietly
WT_DB::exec("COMMIT");
exit;
}
header('Content-type: text/html; charset=UTF-8');
if ($row->import_offset==0 || $row->import_total==0) {
// Finished? Show the maintenance links, similar to editgedcoms.php
WT_DB::exec("COMMIT");
echo "DONE";
exit;
}
// Calculate progress so far
$percent=100*(($row->import_offset-1) / $row->import_total);
$status=i18n::translate('Loading data from GEDCOM: %.1f%%', $percent);
echo
'
', htmlspecialchars($status), '
',
WT_JS_START,
'$("#progressbar', $gedcom_id, '").progressbar({value: ', round($percent, 1), '});',
WT_JS_END,
flush();
// Run for one second. This keeps the resource requirements low.
for ($end_time=microtime(true)+1.0; microtime(true)<$end_time; ) {
// If we are at the start position, do some tidying up
if ($row->import_offset==1) {
$keep_media=safe_GET_bool('keep_media');
// Delete any existing genealogical data
empty_database($gedcom_id, $keep_media);
set_gedcom_setting($gedcom_id, 'imported', false);
// Remove any byte-order-mark
WT_DB::prepare(
"UPDATE {$TBLPREFIX}gedcom".
" SET import_gedcom=TRIM(LEADING ? FROM import_gedcom)".
" WHERE gedcom_id=?"
)->execute(array(WT_UTF8_BOM, $gedcom_id));
// Convert line endings. Don't convert \r\n - it is very slow. Just deal
// with empty records later.
WT_DB::prepare(
"UPDATE {$TBLPREFIX}gedcom".
" SET import_gedcom=REPLACE(import_gedcom, '\r', '\n')".
" WHERE gedcom_id=?"
)->execute(array($gedcom_id));
// Fetch the header record
$data=WT_DB::prepare(
"SELECT LEFT(import_gedcom, CASE LOCATE('\n0', import_gedcom, 2) WHEN 0 THEN LENGTH(import_gedcom) ELSE LOCATE('\n0', import_gedcom, 2) END)".
" FROM {$TBLPREFIX}gedcom".
" WHERE gedcom_id=?"
)->execute(array($gedcom_id))->fetchOne();
WT_DB::prepare(
"UPDATE {$TBLPREFIX}gedcom".
" SET import_offset=?".
" WHERE gedcom_id=?"
)->execute(array(strlen($data)+1, $gedcom_id));
if (substr($data, 0, 6)!='0 HEAD') {
WT_DB::exec("ROLLBACK");
echo i18n::translate('Invalid GEDCOM file - no header record found.');
echo WT_JS_START, '$("#actions', $gedcom_id, '").toggle();', WT_JS_END;
exit;
}
// What character set is this? Need to convert it to UTF8
if (preg_match('/\n1\s*CHAR(?:ACTER)?\s+(.+)/', $data, $match)) {
$charset=strtoupper($match[1]);
} else {
$charset='ASCII';
}
// MySQL supports a wide range of collation conversions. These are ones that
// have been encountered "in the wild".
switch ($charset) {
case 'ANSI':
case 'ASCII':
WT_DB::prepare(
"UPDATE {$TBLPREFIX}gedcom".
" SET import_gedcom=CONVERT(CONVERT(import_gedcom USING ascii) USING utf8)".
" WHERE gedcom_id=?"
)->execute(array($gedcom_id));
break;
case 'IBMPC': // IBMPC and MS_DOS could be anything. Mostly it means CP850.
case 'MS-DOS':
case 'CP437':
case 'CP850':
// CP850 has extra letters with diacritics to replace box-drawing chars in CP437.
WT_DB::prepare(
"UPDATE {$TBLPREFIX}gedcom".
" SET import_gedcom=CONVERT(CONVERT(import_gedcom USING cp850) USING utf8)".
" WHERE gedcom_id=?"
)->execute(array($gedcom_id));
break;
case 'MACINTOSH':
// Convert from MAC Roman to UTF8.
WT_DB::prepare(
"UPDATE {$TBLPREFIX}gedcom".
" SET import_gedcom=CONVERT(CONVERT(import_gedcom USING macroman) USING utf8)".
" WHERE gedcom_id=?"
)->execute(array($gedcom_id));
break;
case 'UTF8':
case 'UTF-8':
// Already UTF-8 so nothing to do!
break;
case 'ANSEL':
// TODO: fisharebest has written a mysql stored procedure that converts ANSEL to UTF-8
default:
WT_DB::exec("ROLLBACK");
echo '', i18n::translate('Error: cannot convert GEDCOM file from %s encoding to UTF-8 encoding.', $charset), '';
echo WT_JS_START, '$("#actions', $gedcom_id, '").toggle();', WT_JS_END;
exit;
}
$data=preg_replace('/\n1 CHAR.*(\n[2-9].+)*/', '', $data)."\n1 CHAR UTF-8";
import_record(trim($data), $gedcom_id, false);
} else {
// Fetch the next block of data. At least 64KB, and ending on a record boundary.
$data=WT_DB::prepare(
"SELECT".
" CASE LOCATE('\n0', import_gedcom, import_offset+65536)".
" WHEN 0 THEN SUBSTR(import_gedcom FROM import_offset)".
" ELSE SUBSTR(import_gedcom FROM import_offset FOR LOCATE('\n0', import_gedcom, import_offset+65536)-import_offset)".
" END".
" FROM {$TBLPREFIX}gedcom".
" WHERE gedcom_id=?"
)->execute(array($gedcom_id))->fetchOne();
WT_DB::prepare(
"UPDATE {$TBLPREFIX}gedcom".
" SET import_offset=import_offset+?".
" WHERE gedcom_id=?"
)->execute(array(strlen($data), $gedcom_id));
echo WT_JS_START, WT_JS_END;
foreach (preg_split('/\n(?=0)/', $data) as $rec) {
if ($rec) {
try {
import_record(trim($rec), $gedcom_id, false);
} catch (PDOException $ex) {
// A fatal error. Nothing we can do.
WT_DB::exec("ROLLBACK");
echo '', $ex->getMessage(), '';
echo WT_JS_START, '$("#actions', $gedcom_id, '").toggle();', WT_JS_END;
exit;
}
}
}
}
}
if ($row->import_offset>$row->import_total) {
// Done
set_gedcom_setting($gedcom_id, 'imported', true);
WT_DB::prepare(
"UPDATE {$TBLPREFIX}gedcom".
" SET import_offset=0".
" WHERE gedcom_id=?"
)->execute(array($gedcom_id));
echo
WT_JS_START,
'$("#import', $gedcom_id, '").toggle();',
'$("#actions', $gedcom_id, '").toggle();',
WT_JS_END;
} else {
// Reload.....
echo
WT_JS_START,
'$("#import', $gedcom_id, '").load("import.php?gedcom_id=', $gedcom_id, '");',
WT_JS_END;
}
WT_DB::exec("COMMIT");