/**
* The media firewall passes in an image
* this function can manipulate the image however it wants
* before returning it back to the media firewall
*
* @param resource $im
* @param Tree $tree
*
* @return resource
*/
function applyWatermark($im, Tree $tree)
{
// text to watermark with
$word1_text = $tree->getTitle();
// maximum font size for “word1” ; will be automaticaly reduced to fit in the image
$word1_maxsize = 100;
// rgb color codes for text
$word1_color = '0,0,0';
// ttf font file to use
$word1_font = WT_ROOT . Config::FONT_DEJAVU_SANS_TTF;
// vertical position for the text to past; possible values are: top, middle or bottom, across
$word1_vpos = 'across';
// horizontal position for the text to past in media file; possible values are: left, right, top2bottom, bottom2top
// this value is used only if $word1_vpos=across
$word1_hpos = 'left';
$word2_text = $_SERVER['HTTP_HOST'];
$word2_maxsize = 20;
$word2_color = '0,0,0';
$word2_font = WT_ROOT . Config::FONT_DEJAVU_SANS_TTF;
$word2_vpos = 'top';
$word2_hpos = 'top2bottom';
embedText($im, $word1_text, $word1_maxsize, $word1_color, $word1_font, $word1_vpos, $word1_hpos);
embedText($im, $word2_text, $word2_maxsize, $word2_color, $word2_font, $word2_vpos, $word2_hpos);
return $im;
}
/**
* Returns an array of the place hierarchy, based on a random example of place within the GEDCOM.
* It will look for the longest hierarchy in the tree.
* The places are reversed compared to normal GEDCOM structure.
*
* @return array
*/
protected function getPlacesHierarchyFromData()
{
$nb_levels = 0;
//Select all '2 PLAC ' tags in the file and create array
$places_list = array();
$ged_data = Database::prepare('SELECT i_gedcom AS gedcom' . ' FROM `##individuals`' . ' WHERE i_gedcom LIKE :gedcom AND i_file = :gedcom_id' . ' UNION ALL' . 'SELECT f_gedcom AS gedcom' . ' FROM `##families`' . ' WHERE f_gedcom LIKE :gedcom AND f_file = :gedcom_id')->execute(array('gedcom' => '%\\n2 PLAC %', 'gedcom_id' => $this->tree->getTreeId()))->fetchOneColumn();
foreach ($ged_data as $ged_datum) {
$matches = null;
preg_match_all('/\\n2 PLAC (.+)/', $ged_datum, $matches);
foreach ($matches[1] as $match) {
$places_list[$match] = true;
}
}
// Unique list of places
$places_list = array_keys($places_list);
//sort the array, limit to unique values, and count them
usort($places_list, array('I18N', 'strcasecmp'));
//calculate maximum no. of levels to display
$has_found_good_example = false;
foreach ($places_list as $place) {
$levels = explode(",", $place);
$parts = count($levels);
if ($parts >= $nb_levels) {
$nb_levels = $parts;
if (!$has_found_good_example) {
$random_place = $place;
if (min(array_map('strlen', $levels)) > 0) {
$has_found_good_example = true;
}
}
}
}
return array_reverse(array_map('trim', explode(',', $random_place)));
}
/**
* Sometimes, we'll know in advance that we need to load a set of records.
* Typically when we load families and their members.
*
* @param Tree $tree
* @param string[] $xrefs
*/
public static function load(Tree $tree, array $xrefs)
{
$args = array('tree_id' => $tree->getTreeId());
$placeholders = array();
foreach (array_unique($xrefs) as $n => $xref) {
if (!isset(self::$gedcom_record_cache[$tree->getTreeId()][$xref])) {
$placeholders[] = ':x' . $n;
$args['x' . $n] = $xref;
}
}
if (!empty($placeholders)) {
$rows = Database::prepare("SELECT i_id AS xref, i_gedcom AS gedcom" . " FROM `##individuals`" . " WHERE i_file = :tree_id AND i_id IN (" . implode(',', $placeholders) . ")")->execute($args)->fetchAll();
foreach ($rows as $row) {
self::getInstance($row->xref, $tree, $row->gedcom);
}
}
}
/**
* Sometimes, we'll know in advance that we need to load a set of records.
* Typically when we load families and their members.
*
* @param Tree $tree
* @param string[] $xrefs
*/
public static function load(Tree $tree, array $xrefs)
{
$sql = '';
$args = array('tree_id' => $tree->getTreeId());
foreach (array_unique($xrefs) as $n => $xref) {
if (!isset(self::$gedcom_record_cache[$tree->getTreeId()][$xref])) {
$sql .= ($n ? ',:x' : ':x') . $n;
$args['x' . $n] = $xref;
}
}
if (count($args) > 1) {
$rows = Database::prepare("SELECT i_id AS xref, i_gedcom AS gedcom" . " FROM `##individuals`" . " WHERE i_file = :tree_id AND i_id IN (" . $sql . ")")->execute($args)->fetchAll();
foreach ($rows as $row) {
self::getInstance($row->xref, $tree, $row->gedcom);
}
}
}
/**
* Return a computed array of statistics about the dispersion of ancestors across the ancestors
* at a specified generation.
* This statistics cannot be used for generations above 11, as it would cause a out of range in MySQL
*
* Format:
* - key : a base-2 representation of the ancestor at generation G for which exclusive ancestors have been found,
* -1 is used for shared ancestors
* For instance base2(0100) = base10(4) represent the maternal grand father
* - values: number of ancestors exclusively in the ancestors of the ancestor in key
*
* For instance a result at generation 3 could be :
* array ( -1 => 12 -> 12 ancestors are shared by the grand-parents
* base10(1) => 32 -> 32 ancestors are exclusive to the paternal grand-father
* base10(2) => 25 -> 25 ancestors are exclusive to the paternal grand-mother
* base10(4) => 12 -> 12 ancestors are exclusive to the maternal grand-father
* base10(8) => 30 -> 30 ancestors are exclusive to the maternal grand-mother
* )
*
* @param int $gen Reference generation
* @return array
*/
public function getAncestorDispersionForGen($gen)
{
if (!$this->is_setup || $gen > 11) {
return array();
}
// Going further than 11 gen will be out of range in the query
return Database::prepare('SELECT branches, count(i_id)' . ' FROM (' . ' SELECT i_id,' . ' CASE' . ' WHEN CEIL(LOG2(SUM(branch))) = LOG2(SUM(branch)) THEN SUM(branch)' . ' ELSE -1' . ' END branches' . ' FROM (' . ' SELECT DISTINCT majs_i_id i_id,' . ' POW(2, FLOOR(majs_sosa / POW(2, (majs_gen - :gen))) - POW(2, :gen -1)) branch' . ' FROM `##maj_sosa`' . ' WHERE majs_gedcom_id = :tree_id AND majs_user_id = :user_id' . ' AND majs_gen >= :gen' . ' ) indistat' . ' GROUP BY i_id' . ') grouped' . ' GROUP BY branches')->execute(array('tree_id' => $this->tree->getTreeId(), 'user_id' => $this->user->getUserId(), 'gen' => $gen))->fetchAssoc() ?: array();
}
/**
* Get a list of modules which (a) provide a specific function and (b) we have permission to see.
*
* We cannot currently use auto-loading for modules, as there may be user-defined
* modules about which the auto-loader knows nothing.
*
* @param Tree $tree
* @param string $component The type of module, such as "tab", "report" or "menu"
*
* @return AbstractModule[]
*/
private static function getActiveModulesByComponent(Tree $tree, $component)
{
$module_names = Database::prepare("SELECT SQL_CACHE module_name" . " FROM `##module`" . " JOIN `##module_privacy` USING (module_name)" . " WHERE gedcom_id = :tree_id AND component = :component AND status = 'enabled' AND access_level >= :access_level" . " ORDER BY CASE component WHEN 'menu' THEN menu_order WHEN 'sidebar' THEN sidebar_order WHEN 'tab' THEN tab_order ELSE 0 END, module_name")->execute(array('tree_id' => $tree->getTreeId(), 'component' => $component, 'access_level' => Auth::accessLevel($tree)))->fetchOneColumn();
$array = array();
foreach ($module_names as $module_name) {
$interface = '\\Fisharebest\\Webtrees\\Module\\Module' . ucfirst($component) . 'Interface';
$module = self::getModuleByName($module_name);
if ($module instanceof $interface) {
$array[$module_name] = $module;
}
}
// The order of menus/sidebars/tabs is defined in the database. Others are sorted by name.
if ($component !== 'menu' && $component !== 'sidebar' && $component !== 'tab') {
uasort($array, function (AbstractModule $x, AbstractModule $y) {
return I18N::strcasecmp($x->getTitle(), $y->getTitle());
});
}
return $array;
}
/**
* Upgrade to to the next version
*/
public function upgrade()
{
// - changes to the values for the gedcom setting SHOW_RELATIVES_EVENTS
$settings = Database::prepare("SELECT gedcom_id, setting_value FROM `##gedcom_setting` WHERE setting_name='SHOW_RELATIVES_EVENTS'")->fetchAssoc();
foreach ($settings as $gedcom_id => $setting) {
// Delete old settings
$setting = preg_replace('/_(BIRT|MARR|DEAT)_(COUS|MSIB|FSIB|GGCH|NEPH|GGPA)/', '', $setting);
$setting = preg_replace('/_FAMC_(RESI_EMIG)/', '', $setting);
// Rename settings
$setting = preg_replace('/_MARR_(MOTH|FATH|FAMC)/', '_MARR_PARE', $setting);
$setting = preg_replace('/_DEAT_(MOTH|FATH)/', '_DEAT_PARE', $setting);
// Remove duplicates
preg_match_all('/[_A-Z]+/', $setting, $match);
// And save
Tree::findById($gedcom_id)->setPreference('SHOW_RELATIVES_EVENTS', implode(',', array_unique($match[0])));
}
}
http_response_code(403);
return;
}
$controller = new AjaxController();
$controller->pageHeader();
// Don't allow the user to cancel the request. We do not want to be left
// with an incomplete transaction.
ignore_user_abort(true);
// Run in a transaction
Database::beginTransaction();
// Only allow one process to import each gedcom at a time
Database::prepare("SELECT * FROM `##gedcom_chunk` WHERE gedcom_id=? FOR UPDATE")->execute(array($gedcom_id));
// What is the current import status?
$row = Database::prepare("SELECT" . " SUM(IF(imported, LENGTH(chunk_data), 0)) AS import_offset," . " SUM(LENGTH(chunk_data)) AS import_total" . " FROM `##gedcom_chunk` WHERE gedcom_id=?")->execute(array($gedcom_id))->fetchOneRow();
if ($row->import_offset == $row->import_total) {
Tree::findById($gedcom_id)->setPreference('imported', '1');
// Finished? Show the maintenance links, similar to admin_trees_manage.php
Database::commit();
$controller->addInlineJavascript('jQuery("#import' . $gedcom_id . '").addClass("hidden");' . 'jQuery("#actions' . $gedcom_id . '").removeClass("hidden");');
return;
}
// Calculate progress so far
$progress = $row->import_offset / $row->import_total;
?>
<div class="progress" id="progress<?php
echo $gedcom_id;
?>
">
<div
class="progress-bar"
role="progressbar"
<?php
echo I18N::translate('After creating the family tree, you will be able to import data from a GEDCOM file.');
?>
</p>
</div>
</div>
</form>
</div>
</div>
</div>
<?php
}
?>
<!-- display link to PhpGedView-WT transfer wizard on first visit to this page, before any GEDCOM is loaded -->
<?php
if (count(Tree::GetAll()) === 0 && count(User::all()) === 1) {
?>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">
<i class="fa fa-fw fa-magic"></i>
<a data-toggle="collapse" data-parent="#accordion" href="#pgv-import-wizard">
<?php
echo I18N::translate('PhpGedView to webtrees transfer wizard');
?>
</a>
</h2>
</div>
<div id="pgv-import-wizard" class="panel-collapse collapse">
<div class="panel-body">
<p>
请发表评论