/**
  * get edit menu
  */
 public function getEditMenu()
 {
     if (!$this->record || $this->record->isPendingDeletion()) {
         return null;
     }
     // edit menu
     $menu = new Menu(I18N::translate('Edit'), '#', 'menu-record');
     // edit raw
     if (Auth::isAdmin() || Auth::isEditor($this->record->getTree()) && $this->record->getTree()->getPreference('SHOW_GEDCOM_RECORD')) {
         $menu->addSubmenu(new Menu(I18N::translate('Edit raw GEDCOM'), '#', 'menu-record-editraw', array('onclick' => 'return edit_raw("' . $this->record->getXref() . '");')));
     }
     // delete
     if (Auth::isEditor($this->record->getTree())) {
         $menu->addSubmenu(new Menu(I18N::translate('Delete'), '#', 'menu-record-del', array('onclick' => 'return delete_record("' . I18N::translate('Are you sure you want to delete “%s”?', Filter::escapeJs(Filter::unescapeHtml($this->record->getFullName()))) . '", "' . $this->record->getXref() . '");')));
     }
     // add to favorites
     if (Module::getModuleByName('user_favorites')) {
         $menu->addSubmenu(new Menu(I18N::translate('Add to favorites'), '#', 'menu-record-addfav', array('onclick' => 'jQuery.post("module.php?mod=user_favorites&mod_action=menu-add-favorite" ,{xref:"' . $this->record->getXref() . '"},function(){location.reload();})')));
     }
     // Get the link for the first submenu and set it as the link for the main menu
     if ($menu->getSubmenus()) {
         $submenus = $menu->getSubmenus();
         $menu->setLink($submenus[0]->getLink());
         $menu->setAttrs($submenus[0]->getAttrs());
     }
     return $menu;
 }
Exemple #2
0
 /**
  * imagettftext is the function that is most likely to throw an error
  * use this custom error handler to catch and log it
  *
  * @param int    $errno
  * @param string $errstr
  *
  * @return bool
  */
 function imageTtfTextErrorHandler($errno, $errstr)
 {
     // log the error
     Log::addErrorLog('Image Builder error: >' . $errno . '/' . $errstr . '< while processing file >' . $this->media->getServerFilename() . '<');
     // change value of useTTF to false so the fallback watermarking can be used.
     $this->use_ttf = false;
     return true;
 }
 /**
  * get edit menu
  */
 public function getEditMenu()
 {
     if (!$this->record || $this->record->isPendingDeletion()) {
         return null;
     }
     // edit menu
     $menu = new Menu(I18N::translate('Edit'), '#', 'menu-record');
     // edit raw
     if (Auth::isAdmin() || Auth::isEditor($this->record->getTree()) && $this->record->getTree()->getPreference('SHOW_GEDCOM_RECORD')) {
         $menu->addSubmenu(new Menu(I18N::translate('Edit the raw GEDCOM'), '#', 'menu-record-editraw', array('onclick' => 'return edit_raw("' . $this->record->getXref() . '");')));
     }
     // delete
     if (Auth::isEditor($this->record->getTree())) {
         $menu->addSubmenu(new Menu(I18N::translate('Delete'), '#', 'menu-record-del', array('onclick' => 'return delete_record("' . I18N::translate('Are you sure you want to delete “%s”?', Filter::escapeJs(Filter::unescapeHtml($this->record->getFullName()))) . '", "' . $this->record->getXref() . '");')));
     }
     return $menu;
 }
Exemple #4
0
 /**
  * Extends the Media constructor.
  * Create a certificate from the file path
  * @param string $data
  * @param Tree $tree Reference tree
  * @param CertificateProviderInterface $provider
  */
 public function __construct($data, Tree $tree, CertificateProviderInterface $provider)
 {
     $this->provider = $provider;
     // Data is only the file name
     $data = str_replace("\\", '/', $data);
     $xref = Functions::encryptToSafeBase64($data);
     $gedcom = sprintf('0 @%1$s@ OBJE' . PHP_EOL . '1 FILE %2$s', $xref, $data);
     parent::__construct($xref, $gedcom, '', $tree);
     $this->title = basename($this->getFilename(), '.' . $this->extension());
     $match = null;
     $ct = preg_match("/(?<year>\\d{1,4})(\\.(?<month>\\d{1,2}))?(\\.(?<day>\\d{1,2}))?( (?<type>[A-Z]{1,2}) )?(?<details>.*)/", $this->title, $match);
     if ($ct > 0) {
         $monthId = (int) $match['month'];
         $calendarShortMonths = Functions::getCalendarShortMonths();
         $monthShortName = array_key_exists($monthId, $calendarShortMonths) ? $calendarShortMonths[$monthId] : $monthId;
         $this->certDate = new Date($match['day'] . ' ' . strtoupper($monthShortName) . ' ' . $match['year']);
         $this->certType = $match['type'];
         $this->certDetails = $match['details'];
     } else {
         $this->certDetails = $this->title;
     }
 }
 /**
  * Get the current view of a record, allowing for pending changes
  *
  * @param string $xref
  * @param string $type
  *
  * @return string
  */
 public static function getLatestRecord($xref, $type)
 {
     global $WT_TREE;
     switch ($type) {
         case 'INDI':
             return Individual::getInstance($xref, $WT_TREE)->getGedcom();
         case 'FAM':
             return Family::getInstance($xref, $WT_TREE)->getGedcom();
         case 'SOUR':
             return Source::getInstance($xref, $WT_TREE)->getGedcom();
         case 'REPO':
             return Repository::getInstance($xref, $WT_TREE)->getGedcom();
         case 'OBJE':
             return Media::getInstance($xref, $WT_TREE)->getGedcom();
         case 'NOTE':
             return Note::getInstance($xref, $WT_TREE)->getGedcom();
         default:
             return GedcomRecord::getInstance($xref, $WT_TREE)->getGedcom();
     }
 }
    return array_map(function ($y) use($WT_TREE) {
        return Individual::getInstance($y, $WT_TREE);
    }, $tmp);
}, $individuals);
$families = Database::prepare("SELECT GROUP_CONCAT(f_id) AS xrefs " . " FROM `##families`" . " WHERE f_file = :tree_id" . " GROUP BY LEAST(f_husb, f_wife), GREATEST(f_husb, f_wife)" . " HAVING COUNT(f_id) > 1")->execute(array('tree_id' => $WT_TREE->getTreeId()))->fetchAll();
$families = array_map(function (\stdClass $x) use($WT_TREE) {
    $tmp = explode(',', $x->xrefs);
    return array_map(function ($y) use($WT_TREE) {
        return Family::getInstance($y, $WT_TREE);
    }, $tmp);
}, $families);
$media = Database::prepare("SELECT GROUP_CONCAT(m_id) AS xrefs " . " FROM `##media`" . " WHERE m_file = :tree_id" . " GROUP BY m_titl" . " HAVING COUNT(m_id) > 1")->execute(array('tree_id' => $WT_TREE->getTreeId()))->fetchAll();
$media = array_map(function (\stdClass $x) use($WT_TREE) {
    $tmp = explode(',', $x->xrefs);
    return array_map(function ($y) use($WT_TREE) {
        return Media::getInstance($y, $WT_TREE);
    }, $tmp);
}, $media);
$all_duplicates = array(I18N::translate('Repositories') => $repositories, I18N::translate('Sources') => $sources, I18N::translate('Individuals') => $individuals, I18N::translate('Families') => $families, I18N::translate('Media objects') => $media);
?>
<ol class="breadcrumb small">
	<li><a href="admin.php"><?php 
echo I18N::translate('Control panel');
?>
</a></li>
	<li><a href="admin_trees_manage.php"><?php 
echo I18N::translate('Manage family trees');
?>
</a></li>
	<li class="active"><?php 
echo $controller->getPageTitle();
 /**
  * Startup activity
  */
 public function __construct()
 {
     // Automatically fix broken links
     if ($this->record && $this->record->canEdit()) {
         $broken_links = 0;
         foreach ($this->record->getFacts('HUSB|WIFE|CHIL|FAMS|FAMC|REPO') as $fact) {
             if (!$fact->isPendingDeletion() && $fact->getTarget() === null) {
                 $this->record->deleteFact($fact->getFactId(), false);
                 FlashMessages::addMessage(I18N::translate('The link from “%1$s” to “%2$s” has been deleted.', $this->record->getFullName(), $fact->getValue()));
                 $broken_links = true;
             }
         }
         foreach ($this->record->getFacts('NOTE|SOUR|OBJE') as $fact) {
             // These can be links or inline.  Only delete links.
             if (!$fact->isPendingDeletion() && $fact->getTarget() === null && preg_match('/^@.*@$/', $fact->getValue())) {
                 $this->record->deleteFact($fact->getFactId(), false);
                 FlashMessages::addMessage(I18N::translate('The link from “%1$s” to “%2$s” has been deleted.', $this->record->getFullName(), $fact->getValue()));
                 $broken_links = true;
             }
         }
         if ($broken_links) {
             // Reload the updated family
             $this->record = GedcomRecord::getInstance($this->record->getXref(), $this->record->getTree());
         }
     }
     parent::__construct();
     // We want robots to index this page
     $this->setMetaRobots('index,follow');
     // Set a page title
     if ($this->record) {
         if ($this->record->canShowName()) {
             // e.g. "John Doe" or "1881 Census of Wales"
             $this->setPageTitle($this->record->getFullName());
         } else {
             // e.g. "Individual" or "Source"
             $record = $this->record;
             $this->setPageTitle(GedcomTag::getLabel($record::RECORD_TYPE));
         }
     } else {
         // No such record
         $this->setPageTitle(I18N::translate('Private'));
     }
 }
 /**
  * Get all facts containing media links for this person and their spouse-family records
  *
  * @return Media[]
  */
 private function getMedia()
 {
     global $controller;
     if ($this->media_list === null) {
         // Use facts from this individual and all their spouses
         $facts = $controller->record->getFacts();
         foreach ($controller->record->getSpouseFamilies() as $family) {
             foreach ($family->getFacts() as $fact) {
                 $facts[] = $fact;
             }
         }
         // Use all media from each fact
         $this->media_list = array();
         foreach ($facts as $fact) {
             // Don't show pending edits, as the user just sees duplicates
             if (!$fact->isPendingDeletion()) {
                 preg_match_all('/(?:^1|\\n\\d) OBJE @(' . WT_REGEX_XREF . ')@/', $fact->getGedcom(), $matches);
                 foreach ($matches[1] as $match) {
                     $media = Media::getInstance($match, $controller->record->getTree());
                     if ($media && $media->canShow()) {
                         $this->media_list[] = $media;
                     }
                 }
             }
         }
         // If a media object is linked twice, only show it once
         $this->media_list = array_unique($this->media_list);
         // Sort these using _WT_OBJE_SORT
         $wt_obje_sort = array();
         foreach ($controller->record->getFacts('_WT_OBJE_SORT') as $fact) {
             $wt_obje_sort[] = trim($fact->getValue(), '@');
         }
         usort($this->media_list, function (Media $x, Media $y) use($wt_obje_sort) {
             return array_search($x->getXref(), $wt_obje_sort) - array_search($y->getXref(), $wt_obje_sort);
         });
     }
     return $this->media_list;
 }
Exemple #9
0
            if ($media && $media->canShow()) {
                $sort_obje[] = $media;
            }
        }
        // Add other media objects from the individual and any spouse-families
        $record_list = array($person);
        foreach ($person->getSpouseFamilies() as $family) {
            $record_list[] = $family;
        }
        foreach ($record_list as $record) {
            if ($record->canShow()) {
                foreach ($record->getFacts() as $fact) {
                    if (!$fact->isPendingDeletion()) {
                        preg_match_all('/(?:^1|\\n\\d) OBJE @(' . WT_REGEX_XREF . ')@/', $fact->getGedcom(), $matches);
                        foreach ($matches[1] as $match) {
                            $media = Media::getInstance($match, $WT_TREE);
                            if (!in_array($media, $sort_obje)) {
                                $sort_obje[] = $media;
                            }
                        }
                    }
                }
            }
        }
        ?>
	<div id="edit_interface-page">
		<h4><?php 
        echo I18N::translate('Click a row, then drag-and-drop to re-order media');
        ?>
</h4>
		<form name="reorder_form" method="post" action="edit_interface.php">
Exemple #10
0
 /**
  * Generate a filtered, sourced, privacy-checked list of media objects - for the media list.
  *
  * @param string $folder     folder to search
  * @param string $subfolders either "include" or "exclude"
  * @param string $sort       either "file" or "title"
  * @param string $filter     optional search string
  * @param string $form_type  option OBJE/FILE/FORM/TYPE
  *
  * @throws \Exception
  *
  * @return Media[]
  */
 public static function mediaList($folder, $subfolders, $sort, $filter, $form_type)
 {
     global $WT_TREE;
     // All files in the folder, plus external files
     $sql = "SELECT m_id AS xref, m_gedcom AS gedcom" . " FROM `##media`" . " WHERE m_file=?";
     $args = array($WT_TREE->getTreeId());
     // Only show external files when we are looking at the root folder
     if ($folder == '') {
         $sql_external = " OR m_filename LIKE 'http://%' OR m_filename LIKE 'https://%'";
     } else {
         $sql_external = "";
     }
     // Include / exclude subfolders (but always include external)
     switch ($subfolders) {
         case 'include':
             $sql .= " AND (m_filename LIKE CONCAT(?, '%') {$sql_external})";
             $args[] = Filter::escapeLike($folder);
             break;
         case 'exclude':
             $sql .= " AND (m_filename LIKE CONCAT(?, '%')  AND m_filename NOT LIKE CONCAT(?, '%/%') {$sql_external})";
             $args[] = Filter::escapeLike($folder);
             $args[] = Filter::escapeLike($folder);
             break;
         default:
             throw new \Exception('Bad argument (subfolders=' . $subfolders . ') in QueryMedia::mediaList()');
     }
     // Apply search terms
     if ($filter) {
         $sql .= " AND (SUBSTRING_INDEX(m_filename, '/', -1) LIKE CONCAT('%', ?, '%') OR m_titl LIKE CONCAT('%', ?, '%'))";
         $args[] = Filter::escapeLike($filter);
         $args[] = Filter::escapeLike($filter);
     }
     if ($form_type) {
         $sql .= " AND (m_gedcom LIKE CONCAT('%\n3 TYPE ', ?, '%'))";
         $args[] = $form_type;
     }
     switch ($sort) {
         case 'file':
             $sql .= " ORDER BY m_filename";
             break;
         case 'title':
             $sql .= " ORDER BY m_titl";
             break;
         default:
             throw new \Exception('Bad argument (sort=' . $sort . ') in QueryMedia::mediaList()');
     }
     $rows = Database::prepare($sql)->execute($args)->fetchAll();
     $list = array();
     foreach ($rows as $row) {
         $media = Media::getInstance($row->xref, $WT_TREE, $row->gedcom);
         if ($media->canShow()) {
             $list[] = $media;
         }
     }
     return $list;
 }
Exemple #11
0
 /**
  * Media objects linked to this fact
  *
  * @return Media[]
  */
 public function getMedia()
 {
     $media = array();
     preg_match_all('/\\n2 OBJE @(' . WT_REGEX_XREF . ')@/', $this->getGedcom(), $matches);
     foreach ($matches[1] as $match) {
         $obje = Media::getInstance($match, $this->getParent()->getTree());
         if ($obje->canShow()) {
             $media[] = $obje;
         }
     }
     return $media;
 }
 /**
  * XML <Image/>
  *
  * @param array $attrs an array of key value pairs for the attributes
  */
 private function imageStartHandler($attrs)
 {
     global $WT_TREE;
     // mixed Position the top corner of this box on the page. the default is the current position
     $top = '.';
     if (isset($attrs['top'])) {
         if ($attrs['top'] === "0") {
             $top = 0;
         } elseif ($attrs['top'] === '.') {
             $top = '.';
         } elseif (!empty($attrs['top'])) {
             $top = (int) $attrs['top'];
         }
     }
     // mixed Position the left corner of this box on the page. the default is the current position
     $left = '.';
     if (isset($attrs['left'])) {
         if ($attrs['left'] === '0') {
             $left = 0;
         } elseif ($attrs['left'] === '.') {
             $left = '.';
         } elseif (!empty($attrs['left'])) {
             $left = (int) $attrs['left'];
         }
     }
     // string Align the image in left, center, right
     $align = '';
     if (!empty($attrs['align'])) {
         $align = $attrs['align'];
     }
     // string Next Line should be T:next to the image, N:next line
     $ln = 'T';
     if (!empty($attrs['ln'])) {
         $ln = $attrs['ln'];
     }
     $width = 0;
     $height = 0;
     if (!empty($attrs['width'])) {
         $width = (int) $attrs['width'];
     }
     if (!empty($attrs['height'])) {
         $height = (int) $attrs['height'];
     }
     $file = '';
     if (!empty($attrs['file'])) {
         $file = $attrs['file'];
     }
     if ($file == "@FILE") {
         $match = array();
         if (preg_match("/\\d OBJE @(.+)@/", $this->gedrec, $match)) {
             $mediaobject = Media::getInstance($match[1], $WT_TREE);
             $attributes = $mediaobject->getImageAttributes('thumb');
             if (in_array($attributes['ext'], array('GIF', 'JPG', 'PNG', 'SWF', 'PSD', 'BMP', 'TIFF', 'TIFF', 'JPC', 'JP2', 'JPX', 'JB2', 'SWC', 'IFF', 'WBMP', 'XBM')) && $mediaobject->canShow() && $mediaobject->fileExists('thumb')) {
                 if ($width > 0 && $height == 0) {
                     $perc = $width / $attributes['adjW'];
                     $height = round($attributes['adjH'] * $perc);
                 } elseif ($height > 0 && $width == 0) {
                     $perc = $height / $attributes['adjH'];
                     $width = round($attributes['adjW'] * $perc);
                 } else {
                     $width = $attributes['adjW'];
                     $height = $attributes['adjH'];
                 }
                 $image = $this->report_root->createImageFromObject($mediaobject, $left, $top, $width, $height, $align, $ln);
                 $this->wt_report->addElement($image);
             }
         }
     } else {
         if (file_exists($file) && preg_match("/(jpg|jpeg|png|gif)\$/i", $file)) {
             $size = getimagesize($file);
             if ($width > 0 && $height == 0) {
                 $perc = $width / $size[0];
                 $height = round($size[1] * $perc);
             } elseif ($height > 0 && $width == 0) {
                 $perc = $height / $size[1];
                 $width = round($size[0] * $perc);
             } else {
                 $width = $size[0];
                 $height = $size[1];
             }
             $image = $this->report_root->createImage($file, $left, $top, $width, $height, $align, $ln);
             $this->wt_report->addElement($image);
         }
     }
 }
 echo '<tr><td class="topbottombar" colspan="2">';
 echo I18N::translate('Link to an existing media object');
 echo '</td></tr><tr><td class="descriptionbox width20 wrap">', I18N::translate('Media'), '</td>';
 echo '<td class="optionbox wrap">';
 if (!empty($mediaid)) {
     //-- Get the title of this existing Media item
     $title = Database::prepare("SELECT m_titl FROM `##media` where m_id=? AND m_file=?")->execute(array($mediaid, $WT_TREE->getTreeId()))->fetchOne();
     if ($title) {
         echo '<b>', $title, '</b>';
     } else {
         echo '<b>', $mediaid, '</b>';
     }
     echo '<table><tr><td>';
     //-- Get the filename of this existing Media item
     $filename = Database::prepare("SELECT m_filename FROM `##media` where m_id=? AND m_file=?")->execute(array($mediaid, $WT_TREE->getTreeId()))->fetchOne();
     $media = Media::getInstance($mediaid, $WT_TREE);
     echo $media->displayImage();
     echo '</td></tr></table>';
     echo '</td></tr>';
     echo '<tr><td class="descriptionbox width20 wrap">', I18N::translate('Links'), '</td>';
     echo '<td class="optionbox wrap">';
     echo '<table><tr><td>';
     echo '<table id="existLinkTbl" width="430" cellspacing="1" >';
     echo '<tr>';
     echo '<td class="topbottombar" width="15"  style="font-weight:100;" >#</td>';
     echo '<td class="topbottombar" width="50"  style="font-weight:100;" >', I18N::translate('Record'), '</td>';
     echo '<td class="topbottombar" width="340" style="font-weight:100;" >', I18N::translate('Name'), '</td>';
     echo '<td class="topbottombar" width="20"  style="font-weight:100;" >', I18N::translate('Keep'), '</td>';
     echo '<td class="topbottombar" width="20"  style="font-weight:100;" >', I18N::translate('Remove'), '</td>';
     echo '<td class="topbottombar" width="20"  style="font-weight:100;" >', I18N::translate('Family navigator'), '</td>';
     echo "</tr>";
Exemple #14
0
/**
 * Generate some useful information and links about a media object.
 *
 * @param Media $media
 *
 * @return string HTML
 */
function mediaObjectInfo(Media $media)
{
    $xref = $media->getXref();
    $gedcom = $media->getTree()->getName();
    $html = '<div class="btn-group"><button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><i class="fa fa-pencil"></i> <span class="caret"></span></button><ul class="dropdown-menu" role="menu">' . '<li><a href="#" onclick="window.open(\'addmedia.php?action=editmedia&amp;pid=' . $xref . '&ged=' . Filter::escapeJs($gedcom) . '\', \'_blank\', edit_window_specs);"><i class="fa fa-fw fa-pencil"></i> ' . I18N::translate('Edit') . '</a></li>' . '<li><a href="#" onclick="return delete_record(\'' . I18N::translate('Are you sure you want to delete “%s”?', Filter::escapeJs(Filter::unescapeHtml($media->getFullName()))) . '\', \'' . $media->getXref() . '\', \'' . Filter::escapeJs($gedcom) . '\');"><i class="fa fa-fw fa-trash-o"></i> ' . I18N::translate('Delete') . '</a></li>' . '<li><a href="#" onclick="return ilinkitem(\'' . $media->getXref() . '\', \'person\', WT_GEDCOM)"><i class="fa fa-fw fa-link"></i> ' . I18N::translate('Link this media object to an individual') . '</a></li>' . '<li><a href="#" onclick="return ilinkitem(\'' . $media->getXref() . '\', \'family\', WT_GEDCOM)"><i class="fa fa-fw fa-link"></i> ' . I18N::translate('Link this media object to a family') . '</a></li>' . '<li><a href="#" onclick="return ilinkitem(\'' . $media->getXref() . '\', \'source\', WT_GEDCOM)"><i class="fa fa-fw fa-link"></i> ' . I18N::translate('Link this media object to a source') . '</a></li>';
    if (Module::getModuleByName('GEDFact_assistant')) {
        $html .= '<li><a href="#" onclick="return ilinkitem(\'' . $media->getXref() . '\', \'manage\', WT_GEDCOM)"><i class="fa fa-fw fa-link"></i> ' . I18N::translate('Manage the links') . '</a></li>';
    }
    $html .= '</ul></div> ' . '<b><a href="' . $media->getHtmlUrl() . '">' . $media->getFullName() . '</a></b>' . '<div><i>' . Filter::escapeHtml($media->getNote()) . '</i></div>';
    $html .= '<br>';
    $linked = array();
    foreach ($media->linkedIndividuals('OBJE') as $link) {
        $linked[] = '<a href="' . $link->getHtmlUrl() . '">' . $link->getFullName() . '</a>';
    }
    foreach ($media->linkedFamilies('OBJE') as $link) {
        $linked[] = '<a href="' . $link->getHtmlUrl() . '">' . $link->getFullName() . '</a>';
    }
    foreach ($media->linkedSources('OBJE') as $link) {
        $linked[] = '<a href="' . $link->getHtmlUrl() . '">' . $link->getFullName() . '</a>';
    }
    foreach ($media->linkedNotes('OBJE') as $link) {
        // Invalid GEDCOM - you cannot link a NOTE to an OBJE
        $linked[] = '<a href="' . $link->getHtmlUrl() . '">' . $link->getFullName() . '</a>';
    }
    foreach ($media->linkedRepositories('OBJE') as $link) {
        // Invalid GEDCOM - you cannot link a REPO to an OBJE
        $linked[] = '<a href="' . $link->getHtmlUrl() . '">' . $link->getFullName() . '</a>';
    }
    if ($linked) {
        $html .= '<ul>';
        foreach ($linked as $link) {
            $html .= '<li>' . $link . '</li>';
        }
        $html .= '</ul>';
    } else {
        $html .= '<div class="alert alert-danger">' . I18N::translate('This media object is not linked to any other record.') . '</div>';
    }
    return $html;
}
Exemple #15
0
 /**
  * A separate file for each family tree and each record type.
  * These files depend on access levels, so only cache for visitors.
  *
  * @param int    $ged_id
  * @param string $rec_type
  * @param string $volume
  */
 private function generateFile($ged_id, $rec_type, $volume)
 {
     $tree = Tree::findById($ged_id);
     // Check the cache
     $timestamp = $this->getSetting('sitemap-' . $ged_id . '-' . $rec_type . '-' . $volume . '.timestamp');
     if ($timestamp > WT_TIMESTAMP - self::CACHE_LIFE && !Auth::check()) {
         $data = $this->getSetting('sitemap-' . $ged_id . '-' . $rec_type . '-' . $volume . '.xml');
     } else {
         $data = '<url><loc>' . WT_BASE_URL . 'index.php?ctype=gedcom&amp;ged=' . $tree->getNameUrl() . '</loc></url>' . PHP_EOL;
         $records = array();
         switch ($rec_type) {
             case 'i':
                 $rows = Database::prepare("SELECT i_id AS xref, i_gedcom AS gedcom" . " FROM `##individuals`" . " WHERE i_file = :tree_id" . " ORDER BY i_id" . " LIMIT :limit OFFSET :offset")->execute(array('tree_id' => $ged_id, 'limit' => self::RECORDS_PER_VOLUME, 'offset' => self::RECORDS_PER_VOLUME * $volume))->fetchAll();
                 foreach ($rows as $row) {
                     $records[] = Individual::getInstance($row->xref, $tree, $row->gedcom);
                 }
                 break;
             case 's':
                 $rows = Database::prepare("SELECT s_id AS xref, s_gedcom AS gedcom" . " FROM `##sources`" . " WHERE s_file = :tree_id" . " ORDER BY s_id" . " LIMIT :limit OFFSET :offset")->execute(array('tree_id' => $ged_id, 'limit' => self::RECORDS_PER_VOLUME, 'offset' => self::RECORDS_PER_VOLUME * $volume))->fetchAll();
                 foreach ($rows as $row) {
                     $records[] = Source::getInstance($row->xref, $tree, $row->gedcom);
                 }
                 break;
             case 'r':
                 $rows = Database::prepare("SELECT o_id AS xref, o_gedcom AS gedcom" . " FROM `##other`" . " WHERE o_file = :tree_id AND o_type = 'REPO'" . " ORDER BY o_id" . " LIMIT :limit OFFSET :offset")->execute(array('tree_id' => $ged_id, 'limit' => self::RECORDS_PER_VOLUME, 'offset' => self::RECORDS_PER_VOLUME * $volume))->fetchAll();
                 foreach ($rows as $row) {
                     $records[] = Repository::getInstance($row->xref, $tree, $row->gedcom);
                 }
                 break;
             case 'n':
                 $rows = Database::prepare("SELECT o_id AS xref, o_gedcom AS gedcom" . " FROM `##other`" . " WHERE o_file = :tree_id AND o_type = 'NOTE'" . " ORDER BY o_id" . " LIMIT :limit OFFSET :offset")->execute(array('tree_id' => $ged_id, 'limit' => self::RECORDS_PER_VOLUME, 'offset' => self::RECORDS_PER_VOLUME * $volume))->fetchAll();
                 foreach ($rows as $row) {
                     $records[] = Note::getInstance($row->xref, $tree, $row->gedcom);
                 }
                 break;
             case 'm':
                 $rows = Database::prepare("SELECT m_id AS xref, m_gedcom AS gedcom" . " FROM `##media`" . " WHERE m_file = :tree_id" . " ORDER BY m_id" . " LIMIT :limit OFFSET :offset")->execute(array('tree_id' => $ged_id, 'limit' => self::RECORDS_PER_VOLUME, 'offset' => self::RECORDS_PER_VOLUME * $volume))->fetchAll();
                 foreach ($rows as $row) {
                     $records[] = Media::getInstance($row->xref, $tree, $row->gedcom);
                 }
                 break;
         }
         foreach ($records as $record) {
             if ($record->canShowName()) {
                 $data .= '<url>';
                 $data .= '<loc>' . WT_BASE_URL . $record->getHtmlUrl() . '</loc>';
                 $chan = $record->getFirstFact('CHAN');
                 if ($chan) {
                     $date = $chan->getDate();
                     if ($date->isOK()) {
                         $data .= '<lastmod>' . $date->minimumDate()->Format('%Y-%m-%d') . '</lastmod>';
                     }
                 }
                 $data .= '</url>' . PHP_EOL;
             }
         }
         $data = '<' . '?xml version="1.0" encoding="UTF-8" ?' . '>' . PHP_EOL . '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">' . PHP_EOL . $data . '</urlset>' . PHP_EOL;
         // Cache this data - but only for visitors, as we don’t want
         // visitors to see data created by signed-in users.
         if (!Auth::check()) {
             $this->setSetting('sitemap-' . $ged_id . '-' . $rec_type . '-' . $volume . '.xml', $data);
             $this->setSetting('sitemap-' . $ged_id . '-' . $rec_type . '-' . $volume . '.timestamp', WT_TIMESTAMP);
         }
     }
     header('Content-Type: application/xml');
     header('Content-Length: ' . strlen($data));
     echo $data;
 }
 /**
  * add a new tag input field
  *
  * called for each fact to be edited on a form.
  * Fact level=0 means a new empty form : data are POSTed by name
  * else data are POSTed using arrays :
  * glevels[] : tag level
  *  islink[] : tag is a link
  *     tag[] : tag name
  *    text[] : tag value
  *
  * @param string $tag fact record to edit (eg 2 DATE xxxxx)
  * @param string $upperlevel optional upper level tag (eg BIRT)
  * @param string $label An optional label to echo instead of the default
  * @param string $extra optional text to display after the input field
  * @param Individual $person For male/female translations
  *
  * @return string
  */
 public static function addSimpleTag($tag, $upperlevel = '', $label = '', $extra = null, Individual $person = null)
 {
     global $tags, $main_fact, $xref, $bdm, $action, $WT_TREE;
     // Keep track of SOUR fields, so we can reference them in subsequent PAGE fields.
     static $source_element_id;
     $subnamefacts = array('NPFX', 'GIVN', 'SPFX', 'SURN', 'NSFX', '_MARNM_SURN');
     preg_match('/^(?:(\\d+) (' . WT_REGEX_TAG . ') ?(.*))/', $tag, $match);
     list(, $level, $fact, $value) = $match;
     $level = (int) $level;
     // element name : used to POST data
     if ($level === 0) {
         if ($upperlevel) {
             $element_name = $upperlevel . '_' . $fact;
         } else {
             $element_name = $fact;
         }
     } else {
         $element_name = 'text[]';
     }
     if ($level === 1) {
         $main_fact = $fact;
     }
     // element id : used by javascript functions
     if ($level === 0) {
         $element_id = $fact;
     } else {
         $element_id = $fact . Uuid::uuid4();
     }
     if ($upperlevel) {
         $element_id = $upperlevel . '_' . $fact . Uuid::uuid4();
     }
     // field value
     $islink = substr($value, 0, 1) === '@' && substr($value, 0, 2) !== '@#';
     if ($islink) {
         $value = trim(substr($tag, strlen($fact) + 3), ' @\\r');
     } else {
         $value = (string) substr($tag, strlen($fact) + 3);
     }
     if ($fact === 'REPO' || $fact === 'SOUR' || $fact === 'OBJE' || $fact === 'FAMC') {
         $islink = true;
     }
     if ($fact === 'SHARED_NOTE_EDIT' || $fact === 'SHARED_NOTE') {
         $islink = true;
         $fact = 'NOTE';
     }
     // label
     echo '<tr id="', $element_id, '_tr"';
     if ($fact === 'MAP' || ($fact === 'LATI' || $fact === 'LONG') && $value === '') {
         echo ' style="display:none;"';
     }
     echo '>';
     if (in_array($fact, $subnamefacts) || $fact === 'LATI' || $fact === 'LONG') {
         echo '<td class="optionbox wrap width25">';
     } else {
         echo '<td class="descriptionbox wrap width25">';
     }
     // tag name
     if ($label) {
         echo $label;
     } elseif ($upperlevel) {
         echo GedcomTag::getLabel($upperlevel . ':' . $fact);
     } else {
         echo GedcomTag::getLabel($fact);
     }
     // If using GEDFact-assistant window
     if ($action === 'addnewnote_assisted') {
         // Do not print on GEDFact Assistant window
     } else {
         // Not all facts have help text.
         switch ($fact) {
             case 'NAME':
                 if ($upperlevel !== 'REPO' && $upperlevel !== 'UNKNOWN') {
                     echo FunctionsPrint::helpLink($fact);
                 }
                 break;
             case 'DATE':
             case 'PLAC':
             case 'RESN':
             case 'ROMN':
             case 'SURN':
             case '_HEB':
                 echo FunctionsPrint::helpLink($fact);
                 break;
         }
     }
     // tag level
     if ($level > 0) {
         if ($fact === 'TEXT' && $level > 1) {
             echo '<input type="hidden" name="glevels[]" value="', $level - 1, '">';
             echo '<input type="hidden" name="islink[]" value="0">';
             echo '<input type="hidden" name="tag[]" value="DATA">';
             // leave data text[] value empty because the following TEXT line will cause the DATA to be added
             echo '<input type="hidden" name="text[]" value="">';
         }
         echo '<input type="hidden" name="glevels[]" value="', $level, '">';
         echo '<input type="hidden" name="islink[]" value="', $islink, '">';
         echo '<input type="hidden" name="tag[]" value="', $fact, '">';
     }
     echo '</td>';
     // value
     echo '<td class="optionbox wrap">';
     // retrieve linked NOTE
     if ($fact === 'NOTE' && $islink) {
         $note1 = Note::getInstance($value, $WT_TREE);
         if ($note1) {
             $noterec = $note1->getGedcom();
             preg_match('/' . $value . '/i', $noterec, $notematch);
             $value = $notematch[0];
         }
     }
     // Show names for spouses in MARR/HUSB/AGE and MARR/WIFE/AGE
     if ($fact === 'HUSB' || $fact === 'WIFE') {
         $family = Family::getInstance($xref, $WT_TREE);
         if ($family) {
             $spouse_link = $family->getFirstFact($fact);
             if ($spouse_link) {
                 $spouse = $spouse_link->getTarget();
                 if ($spouse) {
                     echo $spouse->getFullName();
                 }
             }
         }
     }
     if (in_array($fact, Config::emptyFacts()) && ($value === '' || $value === 'Y' || $value === 'y')) {
         echo '<input type="hidden" id="', $element_id, '" name="', $element_name, '" value="', $value, '">';
         if ($level <= 1) {
             echo '<input type="checkbox" ';
             if ($value) {
                 echo 'checked';
             }
             echo ' onclick="document.getElementById(\'' . $element_id . '\').value = (this.checked) ? \'Y\' : \'\';">';
             echo I18N::translate('yes');
         }
         if ($fact === 'CENS' && $value === 'Y') {
             echo self::censusDateSelector(WT_LOCALE, $xref);
             if (Module::getModuleByName('GEDFact_assistant') && GedcomRecord::getInstance($xref, $WT_TREE) instanceof Individual) {
                 echo '<div></div><a href="#" style="display: none;" id="assistant-link" onclick="return activateCensusAssistant();">' . I18N::translate('Create a new shared note using assistant') . '</a></div>';
             }
         }
     } elseif ($fact === 'TEMP') {
         echo self::selectEditControl($element_name, GedcomCodeTemp::templeNames(), I18N::translate('No temple - living ordinance'), $value);
     } elseif ($fact === 'ADOP') {
         echo self::editFieldAdoption($element_name, $value, '', $person);
     } elseif ($fact === 'PEDI') {
         echo self::editFieldPedigree($element_name, $value, '', $person);
     } elseif ($fact === 'STAT') {
         echo self::selectEditControl($element_name, GedcomCodeStat::statusNames($upperlevel), '', $value);
     } elseif ($fact === 'RELA') {
         echo self::editFieldRelationship($element_name, strtolower($value));
     } elseif ($fact === 'QUAY') {
         echo self::selectEditControl($element_name, GedcomCodeQuay::getValues(), '', $value);
     } elseif ($fact === '_WT_USER') {
         echo self::editFieldUsername($element_name, $value);
     } elseif ($fact === 'RESN') {
         echo self::editFieldRestriction($element_name, $value);
     } elseif ($fact === '_PRIM') {
         echo '<select id="', $element_id, '" name="', $element_name, '" >';
         echo '<option value=""></option>';
         echo '<option value="Y" ';
         if ($value === 'Y') {
             echo ' selected';
         }
         echo '>', I18N::translate('always'), '</option>';
         echo '<option value="N" ';
         if ($value === 'N') {
             echo 'selected';
         }
         echo '>', I18N::translate('never'), '</option>';
         echo '</select>';
         echo '<p class="small text-muted">', I18N::translate('Use this image for charts and on the individual’s page.'), '</p>';
     } elseif ($fact === 'SEX') {
         echo '<select id="', $element_id, '" name="', $element_name, '"><option value="M" ';
         if ($value === 'M') {
             echo 'selected';
         }
         echo '>', I18N::translate('Male'), '</option><option value="F" ';
         if ($value === 'F') {
             echo 'selected';
         }
         echo '>', I18N::translate('Female'), '</option><option value="U" ';
         if ($value === 'U' || empty($value)) {
             echo 'selected';
         }
         echo '>', I18N::translateContext('unknown gender', 'Unknown'), '</option></select>';
     } elseif ($fact === 'TYPE' && $level === 3) {
         //-- Build the selector for the Media 'TYPE' Fact
         echo '<select name="text[]"><option selected value="" ></option>';
         $selectedValue = strtolower($value);
         if (!array_key_exists($selectedValue, GedcomTag::getFileFormTypes())) {
             echo '<option selected value="', Filter::escapeHtml($value), '" >', Filter::escapeHtml($value), '</option>';
         }
         foreach (GedcomTag::getFileFormTypes() as $typeName => $typeValue) {
             echo '<option value="', $typeName, '" ';
             if ($selectedValue === $typeName) {
                 echo 'selected';
             }
             echo '>', $typeValue, '</option>';
         }
         echo '</select>';
     } elseif ($fact === 'NAME' && $upperlevel !== 'REPO' && $upperlevel !== 'UNKNOWN' || $fact === '_MARNM') {
         // Populated in javascript from sub-tags
         echo '<input type="hidden" id="', $element_id, '" name="', $element_name, '" onchange="updateTextName(\'', $element_id, '\');" value="', Filter::escapeHtml($value), '" class="', $fact, '">';
         echo '<span id="', $element_id, '_display" dir="auto">', Filter::escapeHtml($value), '</span>';
         echo ' <a href="#edit_name" onclick="convertHidden(\'', $element_id, '\'); return false;" class="icon-edit_indi" title="' . I18N::translate('Edit name') . '"></a>';
     } else {
         // textarea
         if ($fact === 'TEXT' || $fact === 'ADDR' || $fact === 'NOTE' && !$islink) {
             echo '<textarea id="', $element_id, '" name="', $element_name, '" dir="auto">', Filter::escapeHtml($value), '</textarea><br>';
         } else {
             // text
             // If using GEDFact-assistant window
             if ($action === 'addnewnote_assisted') {
                 echo '<input type="text" id="', $element_id, '" name="', $element_name, '" value="', Filter::escapeHtml($value), '" style="width:4.1em;" dir="ltr"';
             } else {
                 echo '<input type="text" id="', $element_id, '" name="', $element_name, '" value="', Filter::escapeHtml($value), '" dir="ltr"';
             }
             echo ' class="', $fact, '"';
             if (in_array($fact, $subnamefacts)) {
                 echo ' onblur="updatewholename();" onkeyup="updatewholename();"';
             }
             // Extra markup for specific fact types
             switch ($fact) {
                 case 'ALIA':
                 case 'ASSO':
                 case '_ASSO':
                     echo ' data-autocomplete-type="ASSO" data-autocomplete-extra="input.DATE"';
                     break;
                 case 'DATE':
                     echo ' onblur="valid_date(this);" onmouseout="valid_date(this);"';
                     break;
                 case 'GIVN':
                     echo ' autofocus data-autocomplete-type="GIVN"';
                     break;
                 case 'LATI':
                     echo ' onblur="valid_lati_long(this, \'N\', \'S\');" onmouseout="valid_lati_long(this, \'N\', \'S\');"';
                     break;
                 case 'LONG':
                     echo ' onblur="valid_lati_long(this, \'E\', \'W\');" onmouseout="valid_lati_long(this, \'E\', \'W\');"';
                     break;
                 case 'NOTE':
                     // Shared notes. Inline notes are handled elsewhere.
                     echo ' data-autocomplete-type="NOTE"';
                     break;
                 case 'OBJE':
                     echo ' data-autocomplete-type="OBJE"';
                     break;
                 case 'PAGE':
                     echo ' data-autocomplete-type="PAGE" data-autocomplete-extra="#' . $source_element_id . '"';
                     break;
                 case 'PLAC':
                     echo ' data-autocomplete-type="PLAC"';
                     break;
                 case 'REPO':
                     echo ' data-autocomplete-type="REPO"';
                     break;
                 case 'SOUR':
                     $source_element_id = $element_id;
                     echo ' data-autocomplete-type="SOUR"';
                     break;
                 case 'SURN':
                 case '_MARNM_SURN':
                     echo ' data-autocomplete-type="SURN"';
                     break;
                 case 'TIME':
                     echo ' pattern="([0-1][0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?" dir="ltr" placeholder="' . I18N::translate('hh:mm or hh:mm:ss') . '"';
                     break;
             }
             echo '>';
         }
         $tmp_array = array('TYPE', 'TIME', 'NOTE', 'SOUR', 'REPO', 'OBJE', 'ASSO', '_ASSO', 'AGE');
         // split PLAC
         if ($fact === 'PLAC') {
             echo '<div id="', $element_id, '_pop" style="display: inline;">';
             echo FunctionsPrint::printSpecialCharacterLink($element_id), ' ', FunctionsPrint::printFindPlaceLink($element_id);
             echo '<span  onclick="jQuery(\'tr[id^=', $upperlevel, '_LATI],tr[id^=', $upperlevel, '_LONG],tr[id^=LATI],tr[id^=LONG]\').toggle(\'fast\'); return false;" class="icon-target" title="', GedcomTag::getLabel('LATI'), ' / ', GedcomTag::getLabel('LONG'), '"></span>';
             echo '</div>';
             if (Module::getModuleByName('places_assistant')) {
                 \PlacesAssistantModule::setup_place_subfields($element_id);
                 \PlacesAssistantModule::print_place_subfields($element_id);
             }
         } elseif (!in_array($fact, $tmp_array)) {
             echo FunctionsPrint::printSpecialCharacterLink($element_id);
         }
     }
     // MARRiage TYPE : hide text field and show a selection list
     if ($fact === 'TYPE' && $level === 2 && $tags[0] === 'MARR') {
         echo '<script>';
         echo 'document.getElementById(\'', $element_id, '\').style.display=\'none\'';
         echo '</script>';
         echo '<select id="', $element_id, '_sel" onchange="document.getElementById(\'', $element_id, '\').value=this.value;" >';
         foreach (array('Unknown', 'Civil', 'Religious', 'Partners') as $key) {
             if ($key === 'Unknown') {
                 echo '<option value="" ';
             } else {
                 echo '<option value="', $key, '" ';
             }
             $a = strtolower($key);
             $b = strtolower($value);
             if ($b !== '' && strpos($a, $b) !== false || strpos($b, $a) !== false) {
                 echo 'selected';
             }
             echo '>', GedcomTag::getLabel('MARR_' . strtoupper($key)), '</option>';
         }
         echo '</select>';
     } elseif ($fact === 'TYPE' && $level === 0) {
         // NAME TYPE : hide text field and show a selection list
         $onchange = 'onchange="document.getElementById(\'' . $element_id . '\').value=this.value;"';
         echo self::editFieldNameType($element_name, $value, $onchange, $person);
         echo '<script>document.getElementById("', $element_id, '").style.display="none";</script>';
     }
     // popup links
     switch ($fact) {
         case 'DATE':
             echo self::printCalendarPopup($element_id);
             break;
         case 'FAMC':
         case 'FAMS':
             echo FunctionsPrint::printFindFamilyLink($element_id);
             break;
         case 'ALIA':
         case 'ASSO':
         case '_ASSO':
             echo FunctionsPrint::printFindIndividualLink($element_id, $element_id . '_description');
             break;
         case 'FILE':
             FunctionsPrint::printFindMediaLink($element_id, '0file');
             break;
         case 'SOUR':
             echo FunctionsPrint::printFindSourceLink($element_id, $element_id . '_description'), ' ', self::printAddNewSourceLink($element_id);
             //-- checkboxes to apply '1 SOUR' to BIRT/MARR/DEAT as '2 SOUR'
             if ($level === 1) {
                 echo '<br>';
                 switch ($WT_TREE->getPreference('PREFER_LEVEL2_SOURCES')) {
                     case '2':
                         // records
                         $level1_checked = 'checked';
                         $level2_checked = '';
                         break;
                     case '1':
                         // facts
                         $level1_checked = '';
                         $level2_checked = 'checked';
                         break;
                     case '0':
                         // none
                     // none
                     default:
                         $level1_checked = '';
                         $level2_checked = '';
                         break;
                 }
                 if (strpos($bdm, 'B') !== false) {
                     echo ' <label><input type="checkbox" name="SOUR_INDI" ', $level1_checked, ' value="1">', I18N::translate('Individual'), '</label>';
                     if (preg_match_all('/(' . WT_REGEX_TAG . ')/', $WT_TREE->getPreference('QUICK_REQUIRED_FACTS'), $matches)) {
                         foreach ($matches[1] as $match) {
                             if (!in_array($match, explode('|', WT_EVENTS_DEAT))) {
                                 echo ' <label><input type="checkbox" name="SOUR_', $match, '" ', $level2_checked, ' value="1">', GedcomTag::getLabel($match), '</label>';
                             }
                         }
                     }
                 }
                 if (strpos($bdm, 'D') !== false) {
                     if (preg_match_all('/(' . WT_REGEX_TAG . ')/', $WT_TREE->getPreference('QUICK_REQUIRED_FACTS'), $matches)) {
                         foreach ($matches[1] as $match) {
                             if (in_array($match, explode('|', WT_EVENTS_DEAT))) {
                                 echo ' <label><input type="checkbox" name="SOUR_', $match, '"', $level2_checked, ' value="1">', GedcomTag::getLabel($match), '</label>';
                             }
                         }
                     }
                 }
                 if (strpos($bdm, 'M') !== false) {
                     echo ' <label><input type="checkbox" name="SOUR_FAM" ', $level1_checked, ' value="1">', I18N::translate('Family'), '</label>';
                     if (preg_match_all('/(' . WT_REGEX_TAG . ')/', $WT_TREE->getPreference('QUICK_REQUIRED_FAMFACTS'), $matches)) {
                         foreach ($matches[1] as $match) {
                             echo ' <label><input type="checkbox" name="SOUR_', $match, '"', $level2_checked, ' value="1">', GedcomTag::getLabel($match), '</label>';
                         }
                     }
                 }
             }
             break;
         case 'REPO':
             echo FunctionsPrint::printFindRepositoryLink($element_id), ' ', self::printAddNewRepositoryLink($element_id);
             break;
         case 'NOTE':
             // Shared Notes Icons ========================================
             if ($islink) {
                 // Print regular Shared Note icons ---------------------------
                 echo ' ', FunctionsPrint::printFindNoteLink($element_id, $element_id . '_description'), ' ', self::printAddNewNoteLink($element_id);
                 if ($value) {
                     echo ' ', self::printEditNoteLink($value);
                 }
             }
             break;
         case 'OBJE':
             echo FunctionsPrint::printFindMediaLink($element_id, '1media');
             if (!$value) {
                 echo ' ', self::printAddNewMediaLink($element_id);
                 $value = 'new';
             }
             break;
     }
     echo '<div id="' . $element_id . '_description">';
     // current value
     if ($fact === 'DATE') {
         $date = new Date($value);
         echo $date->display();
     }
     if (($fact === 'ASSO' || $fact === '_ASSO') && $value === '') {
         if ($level === 1) {
             echo '<p class="small text-muted">' . I18N::translate('An associate is another individual who was involved with this individual, such as a friend or an employer.') . '</p>';
         } else {
             echo '<p class="small text-muted">' . I18N::translate('An associate is another individual who was involved with this fact or event, such as a witness or a priest.') . '</p>';
         }
     }
     if ($value && $value !== 'new' && $islink) {
         switch ($fact) {
             case 'ALIA':
             case 'ASSO':
             case '_ASSO':
                 $tmp = Individual::getInstance($value, $WT_TREE);
                 if ($tmp) {
                     echo ' ', $tmp->getFullName();
                 }
                 break;
             case 'SOUR':
                 $tmp = Source::getInstance($value, $WT_TREE);
                 if ($tmp) {
                     echo ' ', $tmp->getFullName();
                 }
                 break;
             case 'NOTE':
                 $tmp = Note::getInstance($value, $WT_TREE);
                 if ($tmp) {
                     echo ' ', $tmp->getFullName();
                 }
                 break;
             case 'OBJE':
                 $tmp = Media::getInstance($value, $WT_TREE);
                 if ($tmp) {
                     echo ' ', $tmp->getFullName();
                 }
                 break;
             case 'REPO':
                 $tmp = Repository::getInstance($value, $WT_TREE);
                 if ($tmp) {
                     echo ' ', $tmp->getFullName();
                 }
                 break;
         }
     }
     // pastable values
     if ($fact === 'FORM' && $upperlevel === 'OBJE') {
         FunctionsPrint::printAutoPasteLink($element_id, Config::fileFormats());
     }
     echo '</div>', $extra, '</td></tr>';
     return $element_id;
 }
Exemple #17
0
 /** {@inheritdoc} */
 public function modAction($mod_action)
 {
     Database::updateSchema(self::SCHEMA_MIGRATION_PREFIX, self::SCHEMA_SETTING_NAME, self::SCHEMA_TARGET_VERSION);
     switch ($mod_action) {
         case 'admin_config':
             $template = new AdminTemplate();
             return $template->pageContent();
         case 'admin_search':
             // new settings
             $surname = Filter::post('SURNAME');
             $pid = Filter::post('PID');
             if ($surname) {
                 $soundex_std = Filter::postBool('soundex_std');
                 $soundex_dm = Filter::postBool('soundex_dm');
                 $indis = $this->module()->indisArray($surname, $soundex_std, $soundex_dm);
                 usort($indis, 'Fisharebest\\Webtrees\\Individual::compareBirthDate');
                 if (isset($indis) && count($indis) > 0) {
                     $pid = $indis[0]->getXref();
                 } else {
                     $result['error'] = I18N::translate('Error: The surname you entered doesn’t exist in this tree.');
                 }
             }
             if (isset($pid)) {
                 $FTV_SETTINGS = unserialize($this->getSetting('FTV_SETTINGS'));
                 if ($this->module()->searchArray($this->module()->searchArray($FTV_SETTINGS, 'TREE', Filter::getInteger('tree')), 'PID', $pid)) {
                     if ($surname) {
                         $result['error'] = I18N::translate('Error: The root person belonging to this surname already exists');
                     } else {
                         $result['error'] = I18N::translate('Error: A root person with ID %s already exists', $pid);
                     }
                 } else {
                     $record = Individual::getInstance($pid, $this->tree);
                     if ($record) {
                         $root = $record->getFullName() . ' (' . $record->getLifeSpan() . ')';
                         $title = $this->module()->getPageLink($pid);
                         $result = array('access_level' => '2', 'pid' => $pid, 'root' => $root, 'sort' => count($this->module()->searchArray($FTV_SETTINGS, 'TREE', Filter::getInteger('tree'))) + 1, 'surname' => $this->module()->getSurname($pid), 'title' => $title, 'tree' => Filter::getInteger('tree'));
                     } else {
                         if (empty($result['error'])) {
                             $result['error'] = I18N::translate('Error: A person with ID %s does not exist in this tree', $pid);
                         }
                     }
                 }
             }
             echo json_encode($result);
             break;
         case 'admin_add':
             $FTV_SETTINGS = unserialize($this->getSetting('FTV_SETTINGS'));
             $NEW_FTV_SETTINGS = $FTV_SETTINGS;
             $NEW_FTV_SETTINGS[] = array('TREE' => Filter::getInteger('tree'), 'SURNAME' => Filter::post('surname'), 'PID' => Filter::post('pid'), 'ACCESS_LEVEL' => Filter::postInteger('access_level'), 'SORT' => Filter::postInteger('sort'));
             $this->setSetting('FTV_SETTINGS', serialize(array_values($NEW_FTV_SETTINGS)));
             Log::addConfigurationLog($this->getTitle() . ' config updated');
             break;
         case 'admin_update':
             $FTV_SETTINGS = unserialize($this->getSetting('FTV_SETTINGS'));
             $new_surname = Filter::postArray('surname');
             $new_access_level = Filter::postArray('access_level');
             $new_sort = Filter::postArray('sort');
             foreach ($new_surname as $key => $new_surname) {
                 $FTV_SETTINGS[$key]['SURNAME'] = $new_surname;
             }
             foreach ($new_access_level as $key => $new_access_level) {
                 $FTV_SETTINGS[$key]['ACCESS_LEVEL'] = $new_access_level;
             }
             foreach ($new_sort as $key => $new_sort) {
                 $FTV_SETTINGS[$key]['SORT'] = $new_sort;
             }
             $NEW_FTV_SETTINGS = $this->module()->sortArray($FTV_SETTINGS, 'SORT');
             $this->setSetting('FTV_SETTINGS', serialize($NEW_FTV_SETTINGS));
             break;
         case 'admin_save':
             $FTV_OPTIONS = unserialize($this->getSetting('FTV_OPTIONS'));
             $FTV_OPTIONS[Filter::getInteger('tree')] = Filter::postArray('NEW_FTV_OPTIONS');
             $this->setSetting('FTV_OPTIONS', serialize($FTV_OPTIONS));
             Log::addConfigurationLog($this->getTitle() . ' config updated');
             // the cache has to be recreated because the image options could have been changed
             $this->module()->emptyCache();
             break;
         case 'admin_reset':
             $FTV_OPTIONS = unserialize($this->getSetting('FTV_OPTIONS'));
             unset($FTV_OPTIONS[Filter::getInteger('tree')]);
             $this->setSetting('FTV_OPTIONS', serialize($FTV_OPTIONS));
             Log::addConfigurationLog($this->getTitle() . ' options set to default');
             break;
         case 'admin_delete':
             $FTV_SETTINGS = unserialize($this->getSetting('FTV_SETTINGS'));
             unset($FTV_SETTINGS[Filter::getInteger('key')]);
             $this->setSetting('FTV_SETTINGS', serialize($FTV_SETTINGS));
             Log::addConfigurationLog($this->getTitle() . ' item deleted');
             break;
         case 'page':
             $template = new PageTemplate();
             return $template->pageContent();
             // See mediafirewall.php
         // See mediafirewall.php
         case 'thumbnail':
             $mid = Filter::get('mid', WT_REGEX_XREF);
             $media = Media::getInstance($mid, $this->tree);
             $mimetype = $media->mimeType();
             $cache_filename = $this->module()->cacheFileName($media);
             $filetime = filemtime($cache_filename);
             $filetimeHeader = gmdate('D, d M Y H:i:s', $filetime) . ' GMT';
             $expireOffset = 3600 * 24 * 7;
             // tell browser to cache this image for 7 days
             $expireHeader = gmdate('D, d M Y H:i:s', WT_TIMESTAMP + $expireOffset) . ' GMT';
             $etag = $media->getEtag();
             $filesize = filesize($cache_filename);
             // parse IF_MODIFIED_SINCE header from client
             $if_modified_since = 'x';
             if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
                 $if_modified_since = preg_replace('/;.*$/', '', $_SERVER['HTTP_IF_MODIFIED_SINCE']);
             }
             // parse IF_NONE_MATCH header from client
             $if_none_match = 'x';
             if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
                 $if_none_match = str_replace('"', '', $_SERVER['HTTP_IF_NONE_MATCH']);
             }
             // add caching headers.  allow browser to cache file, but not proxy
             header('Last-Modified: ' . $filetimeHeader);
             header('ETag: "' . $etag . '"');
             header('Expires: ' . $expireHeader);
             header('Cache-Control: max-age=' . $expireOffset . ', s-maxage=0, proxy-revalidate');
             // if this file is already in the user’s cache, don’t resend it
             // first check if the if_modified_since param matches
             if ($if_modified_since === $filetimeHeader) {
                 // then check if the etag matches
                 if ($if_none_match === $etag) {
                     http_response_code(304);
                     return;
                 }
             }
             // send headers for the image
             header('Content-Type: ' . $mimetype);
             header('Content-Disposition: filename="' . basename($cache_filename) . '"');
             header('Content-Length: ' . $filesize);
             // Some servers disable fpassthru() and readfile()
             if (function_exists('readfile')) {
                 readfile($cache_filename);
             } else {
                 $fp = fopen($cache_filename, 'rb');
                 if (function_exists('fpassthru')) {
                     fpassthru($fp);
                 } else {
                     while (!feof($fp)) {
                         echo fread($fp, 65536);
                     }
                 }
                 fclose($fp);
             }
             break;
         case 'show_pdf':
             $template = new PdfTemplate();
             return $template->pageBody();
         case 'pdf_data':
             $template = new PdfTemplate();
             return $template->pageData();
         case 'pdf_thumb_data':
             $xref = Filter::get('mid');
             $mediaobject = Media::getInstance($xref, $this->tree);
             $thumb = Filter::get('thumb');
             if ($thumb === '2') {
                 // Fancy thumb
                 echo $this->module()->cacheFileName($mediaobject);
             } else {
                 echo $mediaobject->getServerFilename('thumb');
             }
             break;
         default:
             http_response_code(404);
             break;
     }
 }
Exemple #18
0
 /**
  * Create an image.
  *
  * @param Media $mediaobject
  * @param $x
  * @param $y
  * @param $w
  * @param $h
  * @param $align
  * @param $ln
  *
  * @return ReportHtmlImage
  */
 public function createImageFromObject(Media $mediaobject, $x, $y, $w, $h, $align, $ln)
 {
     return new ReportHtmlImage($mediaobject->getHtmlUrlDirect('thumb'), $x, $y, $w, $h, $align, $ln);
 }
Exemple #19
0
 /**
  * Create a new image object from Media Object - ReportPdf
  *
  * @param Media  $mediaobject
  * @param mixed  $x
  * @param mixed  $y
  * @param int    $w           Image width
  * @param int    $h           Image height
  * @param string $align       L:left, C:center, R:right or empty to use x/y
  * @param string $ln          T:same line, N:next line
  *
  * @return ReportPdfImage
  */
 public function createImageFromObject($mediaobject, $x, $y, $w, $h, $align, $ln)
 {
     return new ReportPdfImage($mediaobject->getServerFilename('thumb'), $x, $y, $w, $h, $align, $ln);
 }
Exemple #20
0
     $fileName = $filename;
 }
 $oldFilename = $media->getFilename();
 $newFilename = $folderName . $fileName;
 // Cannot rename local to external or vice-versa
 if (Functions::isFileExternal($oldFilename) != Functions::isFileExternal($filename)) {
     FlashMessages::addMessage(I18N::translate('The media file %1$s could not be renamed to %2$s.', Html::filename($oldFilename), Html::filename($newFilename)));
     break;
 }
 $messages = false;
 $move_file = false;
 // Move files on disk (if we can) to reflect the change to the GEDCOM data
 if (!$media->isExternal()) {
     $oldServerFile = $media->getServerFilename('main');
     $oldServerThumb = $media->getServerFilename('thumb');
     $newmedia = new Media("xxx", "0 @xxx@ OBJE\n1 FILE " . $newFilename, null, $WT_TREE);
     $newServerFile = $newmedia->getServerFilename('main');
     $newServerThumb = $newmedia->getServerFilename('thumb');
     // We could be either renaming an existing file, or updating a record (with no valid file) to point to a new file
     if ($oldServerFile !== $newServerFile) {
         //-- check if the file is used in more than one gedcom
         //-- do not allow it to be moved or renamed if it is
         if (!$media->isExternal() && FunctionsDb::isMediaUsedInOtherTree($media->getFilename(), $WT_TREE->getTreeId())) {
             FlashMessages::addMessage(I18N::translate('This file is linked to another family tree on this server. It cannot be deleted, moved, or renamed until these links have been removed.'));
             break;
         }
         $move_file = true;
         if (!file_exists($newServerFile) || md5_file($oldServerFile) === md5_file($newServerFile)) {
             try {
                 rename($oldServerFile, $newServerFile);
                 FlashMessages::addMessage(I18N::translate('The media file %1$s has been renamed to %2$s.', Html::filename($oldFilename), Html::filename($newFilename)));
Exemple #21
0
 /**
  * Find the highlighted media object for an individual
  * 1. Ignore all media objects that are not displayable because of Privacy rules
  * 2. Ignore all media objects with the Highlight option set to "N"
  * 3. Pick the first media object that matches these criteria, in order of preference:
  *    (a) Level 1 object with the Highlight option set to "Y"
  *    (b) Level 1 object with the Highlight option missing or set to other than "Y" or "N"
  *    (c) Level 2 or higher object with the Highlight option set to "Y"
  *
  * @return null|Media
  */
 public function findHighlightedMedia()
 {
     $objectA = null;
     $objectB = null;
     $objectC = null;
     // Iterate over all of the media items for the individual
     preg_match_all('/\\n(\\d) OBJE @(' . WT_REGEX_XREF . ')@/', $this->getGedcom(), $matches, PREG_SET_ORDER);
     foreach ($matches as $match) {
         $media = Media::getInstance($match[2], $this->tree);
         if (!$media || !$media->canShow() || $media->isExternal()) {
             continue;
         }
         $level = $match[1];
         $prim = $media->isPrimary();
         if ($prim == 'N') {
             continue;
         }
         if ($level == 1) {
             if ($prim == 'Y') {
                 if (empty($objectA)) {
                     $objectA = $media;
                 }
             } else {
                 if (empty($objectB)) {
                     $objectB = $media;
                 }
             }
         } else {
             if ($prim == 'Y') {
                 if (empty($objectC)) {
                     $objectC = $media;
                 }
             }
         }
     }
     if ($objectA) {
         return $objectA;
     }
     if ($objectB) {
         return $objectB;
     }
     if ($objectC) {
         return $objectC;
     }
     return null;
 }
 /**
  * Check if thumbnails from cache should be recreated
  * 
  * @param type $mediaobject
  * @return string filename
  */
 private function getThumbnail(Media $mediaobject)
 {
     $cache_dir = $this->cacheDir();
     if (!file_exists($cache_dir)) {
         File::mkdir($cache_dir);
     }
     if (file_exists($mediaobject->getServerFilename())) {
         $cache_filename = $this->cacheFileName($mediaobject);
         if (!is_file($cache_filename)) {
             $thumbnail = $this->fancyThumb($mediaobject);
             $mimetype = $mediaobject->mimeType();
             if ($mimetype === 'image/jpeg') {
                 imagejpeg($thumbnail, $cache_filename);
             } elseif ($mimetype === 'image/png') {
                 imagepng($thumbnail, $cache_filename);
             } else {
                 return;
             }
         }
         return $cache_filename;
     }
 }
 /**
  * Print a row for the media tab on the individual page.
  *
  * @param Fact $fact
  * @param int $level
  */
 public static function printMainMedia(Fact $fact, $level)
 {
     $factrec = $fact->getGedcom();
     $parent = $fact->getParent();
     if ($fact->isPendingAddition()) {
         $styleadd = 'new';
         $can_edit = $level == 1 && $fact->canEdit();
     } elseif ($fact->isPendingDeletion()) {
         $styleadd = 'old';
         $can_edit = false;
     } else {
         $styleadd = '';
         $can_edit = $level == 1 && $fact->canEdit();
     }
     // -- find source for each fact
     preg_match_all('/(?:^|\\n)' . $level . ' OBJE @(.*)@/', $factrec, $matches);
     foreach ($matches[1] as $xref) {
         $media = Media::getInstance($xref, $fact->getParent()->getTree());
         // Allow access to "1 OBJE @non_existent_source@", so it can be corrected/deleted
         if (!$media || $media->canShow()) {
             if ($level > 1) {
                 echo '<tr class="row_obje2">';
             } else {
                 echo '<tr>';
             }
             echo '<td class="descriptionbox';
             if ($level > 1) {
                 echo ' rela';
             }
             echo ' ', $styleadd, ' width20">';
             preg_match("/^\\d (\\w*)/", $factrec, $factname);
             $factlines = explode("\n", $factrec);
             // 1 BIRT Y\n2 SOUR ...
             $factwords = explode(" ", $factlines[0]);
             // 1 BIRT Y
             $factname = $factwords[1];
             // BIRT
             if ($factname == 'EVEN' || $factname == 'FACT') {
                 // Add ' EVEN' to provide sensible output for an event with an empty TYPE record
                 $ct = preg_match("/2 TYPE (.*)/", $factrec, $ematch);
                 if ($ct > 0) {
                     $factname = $ematch[1];
                     echo $factname;
                 } else {
                     echo GedcomTag::getLabel($factname, $parent);
                 }
             } elseif ($can_edit) {
                 echo '<a onclick="window.open(\'addmedia.php?action=editmedia&amp;pid=', $media->getXref(), '\', \'_blank\', edit_window_specs); return false;" href="#" title="', I18N::translate('Edit'), '">';
                 echo GedcomTag::getLabel($factname, $parent), '</a>';
                 echo '<div class="editfacts">';
                 echo '<div class="editlink"><a class="editicon" onclick="window.open(\'addmedia.php?action=editmedia&amp;pid=', $media->getXref(), '\', \'_blank\', edit_window_specs); return false;" href="#" title="', I18N::translate('Edit'), '"><span class="link_text">', I18N::translate('Edit'), '</span></a></div>';
                 echo '<div class="copylink"><a class="copyicon" href="#" onclick="jQuery.post(\'action.php\',{action:\'copy-fact\', type:\'\', factgedcom:\'' . rawurlencode($factrec) . '\'},function(){location.reload();})" title="' . I18N::translate('Copy') . '"><span class="link_text">' . I18N::translate('Copy') . '</span></a></div>';
                 echo '<div class="deletelink"><a class="deleteicon" onclick="return delete_fact(\'', I18N::translate('Are you sure you want to delete this fact?'), '\', \'', $parent->getXref(), '\', \'', $fact->getFactId(), '\');" href="#" title="', I18N::translate('Delete'), '"><span class="link_text">', I18N::translate('Delete'), '</span></a></div>';
                 echo '</div>';
             } else {
                 echo GedcomTag::getLabel($factname, $parent);
             }
             echo '</td>';
             echo '<td class="optionbox ', $styleadd, ' wrap">';
             if ($media) {
                 echo '<span class="field">';
                 echo $media->displayImage();
                 echo '<a href="' . $media->getHtmlUrl() . '">';
                 echo '<em>';
                 foreach ($media->getAllNames() as $name) {
                     if ($name['type'] != 'TITL') {
                         echo '<br>';
                     }
                     echo $name['full'];
                 }
                 echo '</em>';
                 echo '</a>';
                 echo '</span>';
                 echo GedcomTag::getLabelValue('FORM', $media->mimeType());
                 $imgsize = $media->getImageAttributes('main');
                 if (!empty($imgsize['WxH'])) {
                     echo GedcomTag::getLabelValue('__IMAGE_SIZE__', $imgsize['WxH']);
                 }
                 if ($media->getFilesizeraw() > 0) {
                     echo GedcomTag::getLabelValue('__FILE_SIZE__', $media->getFilesize());
                 }
                 $mediatype = $media->getMediaType();
                 if ($mediatype) {
                     echo GedcomTag::getLabelValue('TYPE', GedcomTag::getFileFormTypeValue($mediatype));
                 }
                 switch ($media->isPrimary()) {
                     case 'Y':
                         echo GedcomTag::getLabelValue('_PRIM', I18N::translate('yes'));
                         break;
                     case 'N':
                         echo GedcomTag::getLabelValue('_PRIM', I18N::translate('no'));
                         break;
                 }
                 echo FunctionsPrint::printFactNotes($media->getGedcom(), 1);
                 echo self::printFactSources($media->getGedcom(), 1);
             } else {
                 echo $xref;
             }
             echo '</td></tr>';
         }
     }
 }
Exemple #24
0
 /**
  * Create a new media object, from inline media data.
  *
  * @param int    $level
  * @param string $gedrec
  * @param Tree   $tree
  *
  * @return string
  */
 public static function createMediaObject($level, $gedrec, Tree $tree)
 {
     if (preg_match('/\\n\\d FILE (.+)/', $gedrec, $file_match)) {
         $file = $file_match[1];
     } else {
         $file = '';
     }
     if (preg_match('/\\n\\d TITL (.+)/', $gedrec, $file_match)) {
         $titl = $file_match[1];
     } else {
         $titl = '';
     }
     // Have we already created a media object with the same title/filename?
     $xref = Database::prepare("SELECT m_id FROM `##media` WHERE m_filename = ? AND m_titl = ? AND m_file = ?")->execute(array($file, $titl, $tree->getTreeId()))->fetchOne();
     if (!$xref) {
         $xref = $tree->getNewXref('OBJE');
         // renumber the lines
         $gedrec = preg_replace_callback('/\\n(\\d+)/', function ($m) use($level) {
             return "\n" . ($m[1] - $level);
         }, $gedrec);
         // convert to an object
         $gedrec = str_replace("\n0 OBJE\n", '0 @' . $xref . "@ OBJE\n", $gedrec);
         // Fix Legacy GEDCOMS
         $gedrec = preg_replace('/\\n1 FORM (.+)\\n1 FILE (.+)\\n1 TITL (.+)/', "\n1 FILE \$2\n2 FORM \$1\n2 TITL \$3", $gedrec);
         // Fix FTB GEDCOMS
         $gedrec = preg_replace('/\\n1 FORM (.+)\\n1 TITL (.+)\\n1 FILE (.+)/', "\n1 FILE \$3\n2 FORM \$1\n2 TITL \$2", $gedrec);
         // Create new record
         $record = new Media($xref, $gedrec, null, $tree);
         Database::prepare("INSERT INTO `##media` (m_id, m_ext, m_type, m_titl, m_filename, m_file, m_gedcom) VALUES (?, ?, ?, ?, ?, ?, ?)")->execute(array($xref, $record->extension(), $record->getMediaType(), $record->getTitle(), $record->getFilename(), $tree->getTreeId(), $gedrec));
     }
     return "\n" . $level . ' OBJE @' . $xref . '@';
 }
 /**
  * Export the database in GEDCOM format
  *
  * @param Tree $tree Which tree to export
  * @param resource $gedout Handle to a writable stream
  * @param string[] $exportOptions Export options are as follows:
  *                                'privatize':    which Privacy rules apply? (none, visitor, user, manager)
  *                                'toANSI':       should the output be produced in ISO-8859-1 instead of UTF-8? (yes, no)
  *                                'path':         what constant should prefix all media file paths? (eg: media/  or c:\my pictures\my family
  *                                'slashes':      what folder separators apply to media file paths? (forward, backward)
  */
 public static function exportGedcom(Tree $tree, $gedout, $exportOptions)
 {
     switch ($exportOptions['privatize']) {
         case 'gedadmin':
             $access_level = Auth::PRIV_NONE;
             break;
         case 'user':
             $access_level = Auth::PRIV_USER;
             break;
         case 'visitor':
             $access_level = Auth::PRIV_PRIVATE;
             break;
         case 'none':
             $access_level = Auth::PRIV_HIDE;
             break;
     }
     $head = self::gedcomHeader($tree);
     if ($exportOptions['toANSI'] == 'yes') {
         $head = str_replace('UTF-8', 'ANSI', $head);
         $head = utf8_decode($head);
     }
     $head = self::reformatRecord($head);
     fwrite($gedout, $head);
     // Buffer the output. Lots of small fwrite() calls can be very slow when writing large gedcoms.
     $buffer = '';
     // Generate the OBJE/SOUR/REPO/NOTE records first, as their privacy calcualations involve
     // database queries, and we wish to avoid large gaps between queries due to MySQL connection timeouts.
     $tmp_gedcom = '';
     $rows = Database::prepare("SELECT m_id AS xref, m_gedcom AS gedcom" . " FROM `##media` WHERE m_file = :tree_id ORDER BY m_id")->execute(array('tree_id' => $tree->getTreeId()))->fetchAll();
     foreach ($rows as $row) {
         $rec = Media::getInstance($row->xref, $tree, $row->gedcom)->privatizeGedcom($access_level);
         $rec = self::convertMediaPath($rec, $exportOptions['path']);
         if ($exportOptions['toANSI'] === 'yes') {
             $rec = utf8_decode($rec);
         }
         $tmp_gedcom .= self::reformatRecord($rec);
     }
     $rows = Database::prepare("SELECT s_id AS xref, s_file AS gedcom_id, s_gedcom AS gedcom" . " FROM `##sources` WHERE s_file = :tree_id ORDER BY s_id")->execute(array('tree_id' => $tree->getTreeId()))->fetchAll();
     foreach ($rows as $row) {
         $rec = Source::getInstance($row->xref, $tree, $row->gedcom)->privatizeGedcom($access_level);
         if ($exportOptions['toANSI'] === 'yes') {
             $rec = utf8_decode($rec);
         }
         $tmp_gedcom .= self::reformatRecord($rec);
     }
     $rows = Database::prepare("SELECT o_type AS type, o_id AS xref, o_gedcom AS gedcom" . " FROM `##other` WHERE o_file = :tree_id AND o_type NOT IN ('HEAD', 'TRLR') ORDER BY o_id")->execute(array('tree_id' => $tree->getTreeId()))->fetchAll();
     foreach ($rows as $row) {
         switch ($row->type) {
             case 'NOTE':
                 $record = Note::getInstance($row->xref, $tree, $row->gedcom);
                 break;
             case 'REPO':
                 $record = Repository::getInstance($row->xref, $tree, $row->gedcom);
                 break;
             default:
                 $record = GedcomRecord::getInstance($row->xref, $tree, $row->gedcom);
                 break;
         }
         $rec = $record->privatizeGedcom($access_level);
         if ($exportOptions['toANSI'] === 'yes') {
             $rec = utf8_decode($rec);
         }
         $tmp_gedcom .= self::reformatRecord($rec);
     }
     $rows = Database::prepare("SELECT i_id AS xref, i_gedcom AS gedcom" . " FROM `##individuals` WHERE i_file = :tree_id ORDER BY i_id")->execute(array('tree_id' => $tree->getTreeId()))->fetchAll();
     foreach ($rows as $row) {
         $rec = Individual::getInstance($row->xref, $tree, $row->gedcom)->privatizeGedcom($access_level);
         if ($exportOptions['toANSI'] === 'yes') {
             $rec = utf8_decode($rec);
         }
         $buffer .= self::reformatRecord($rec);
         if (strlen($buffer) > 65536) {
             fwrite($gedout, $buffer);
             $buffer = '';
         }
     }
     $rows = Database::prepare("SELECT f_id AS xref, f_gedcom AS gedcom" . " FROM `##families` WHERE f_file = :tree_id ORDER BY f_id")->execute(array('tree_id' => $tree->getTreeId()))->fetchAll();
     foreach ($rows as $row) {
         $rec = Family::getInstance($row->xref, $tree, $row->gedcom)->privatizeGedcom($access_level);
         if ($exportOptions['toANSI'] === 'yes') {
             $rec = utf8_decode($rec);
         }
         $buffer .= self::reformatRecord($rec);
         if (strlen($buffer) > 65536) {
             fwrite($gedout, $buffer);
             $buffer = '';
         }
     }
     fwrite($gedout, $buffer);
     fwrite($gedout, $tmp_gedcom);
     fwrite($gedout, '0 TRLR' . WT_EOL);
 }
Exemple #26
0
    /**
     * Generate the HTML content of this block.
     *
     * @param int      $block_id
     * @param bool     $template
     * @param string[] $cfg
     *
     * @return string
     */
    public function getBlock($block_id, $template = true, $cfg = array())
    {
        global $ctype, $WT_TREE;
        $filter = $this->getBlockSetting($block_id, 'filter', 'all');
        $controls = $this->getBlockSetting($block_id, 'controls', '1');
        $start = $this->getBlockSetting($block_id, 'start', '0') || Filter::getBool('start');
        // We can apply the filters using SQL
        // Do not use "ORDER BY RAND()" - it is very slow on large tables. Use PHP::array_rand() instead.
        $all_media = Database::prepare("SELECT m_id FROM `##media`" . " WHERE m_file = ?" . " AND m_ext  IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, '')" . " AND m_type IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, '')")->execute(array($WT_TREE->getTreeId(), $this->getBlockSetting($block_id, 'filter_avi', '0') ? 'avi' : null, $this->getBlockSetting($block_id, 'filter_bmp', '1') ? 'bmp' : null, $this->getBlockSetting($block_id, 'filter_gif', '1') ? 'gif' : null, $this->getBlockSetting($block_id, 'filter_jpeg', '1') ? 'jpg' : null, $this->getBlockSetting($block_id, 'filter_jpeg', '1') ? 'jpeg' : null, $this->getBlockSetting($block_id, 'filter_mp3', '0') ? 'mp3' : null, $this->getBlockSetting($block_id, 'filter_ole', '1') ? 'ole' : null, $this->getBlockSetting($block_id, 'filter_pcx', '1') ? 'pcx' : null, $this->getBlockSetting($block_id, 'filter_pdf', '0') ? 'pdf' : null, $this->getBlockSetting($block_id, 'filter_png', '1') ? 'png' : null, $this->getBlockSetting($block_id, 'filter_tiff', '1') ? 'tiff' : null, $this->getBlockSetting($block_id, 'filter_wav', '0') ? 'wav' : null, $this->getBlockSetting($block_id, 'filter_audio', '0') ? 'audio' : null, $this->getBlockSetting($block_id, 'filter_book', '1') ? 'book' : null, $this->getBlockSetting($block_id, 'filter_card', '1') ? 'card' : null, $this->getBlockSetting($block_id, 'filter_certificate', '1') ? 'certificate' : null, $this->getBlockSetting($block_id, 'filter_coat', '1') ? 'coat' : null, $this->getBlockSetting($block_id, 'filter_document', '1') ? 'document' : null, $this->getBlockSetting($block_id, 'filter_electronic', '1') ? 'electronic' : null, $this->getBlockSetting($block_id, 'filter_fiche', '1') ? 'fiche' : null, $this->getBlockSetting($block_id, 'filter_film', '1') ? 'film' : null, $this->getBlockSetting($block_id, 'filter_magazine', '1') ? 'magazine' : null, $this->getBlockSetting($block_id, 'filter_manuscript', '1') ? 'manuscript' : null, $this->getBlockSetting($block_id, 'filter_map', '1') ? 'map' : null, $this->getBlockSetting($block_id, 'filter_newspaper', '1') ? 'newspaper' : null, $this->getBlockSetting($block_id, 'filter_other', '1') ? 'other' : null, $this->getBlockSetting($block_id, 'filter_painting', '1') ? 'painting' : null, $this->getBlockSetting($block_id, 'filter_photo', '1') ? 'photo' : null, $this->getBlockSetting($block_id, 'filter_tombstone', '1') ? 'tombstone' : null, $this->getBlockSetting($block_id, 'filter_video', '0') ? 'video' : null))->fetchOneColumn();
        // Keep looking through the media until a suitable one is found.
        $random_media = null;
        while ($all_media) {
            $n = array_rand($all_media);
            $media = Media::getInstance($all_media[$n], $WT_TREE);
            if ($media->canShow() && !$media->isExternal()) {
                // Check if it is linked to a suitable individual
                foreach ($media->linkedIndividuals('OBJE') as $indi) {
                    if ($filter === 'all' || $filter === 'indi' && strpos($indi->getGedcom(), "\n1 OBJE @" . $media->getXref() . '@') !== false || $filter === 'event' && strpos($indi->getGedcom(), "\n2 OBJE @" . $media->getXref() . '@') !== false) {
                        // Found one :-)
                        $random_media = $media;
                        break 2;
                    }
                }
            }
            unset($all_media[$n]);
        }
        $id = $this->getName() . $block_id;
        $class = $this->getName() . '_block';
        if ($ctype === 'gedcom' && Auth::isManager($WT_TREE) || $ctype === 'user' && Auth::check()) {
            $title = '<a class="icon-admin" title="' . I18N::translate('Preferences') . '" href="block_edit.php?block_id=' . $block_id . '&amp;ged=' . $WT_TREE->getNameHtml() . '&amp;ctype=' . $ctype . '"></a>';
        } else {
            $title = '';
        }
        $title .= $this->getTitle();
        if ($random_media) {
            $content = "<div id=\"random_picture_container{$block_id}\">";
            if ($controls) {
                if ($start) {
                    $icon_class = 'icon-media-stop';
                } else {
                    $icon_class = 'icon-media-play';
                }
                $content .= '<div dir="ltr" class="center" id="random_picture_controls' . $block_id . '"><br>';
                $content .= "<a href=\"#\" onclick=\"togglePlay(); return false;\" id=\"play_stop\" class=\"" . $icon_class . "\" title=\"" . I18N::translate('Play') . "/" . I18N::translate('Stop') . '"></a>';
                $content .= '<a href="#" onclick="jQuery(\'#block_' . $block_id . '\').load(\'index.php?ctype=' . $ctype . '&amp;action=ajax&amp;block_id=' . $block_id . '\');return false;" title="' . I18N::translate('Next image') . '" class="icon-media-next"></a>';
                $content .= '</div><script>
					var play = false;
						function togglePlay() {
							if (play) {
								play = false;
								jQuery("#play_stop").removeClass("icon-media-stop").addClass("icon-media-play");
							}
							else {
								play = true;
								playSlideShow();
								jQuery("#play_stop").removeClass("icon-media-play").addClass("icon-media-stop");
							}
						}

						function playSlideShow() {
							if (play) {
								window.setTimeout("reload_image()", 6000);
							}
						}
						function reload_image() {
							if (play) {
								jQuery("#block_' . $block_id . '").load("index.php?ctype=' . $ctype . '&action=ajax&block_id=' . $block_id . '&start=1");
							}
						}
					</script>';
            }
            if ($start) {
                $content .= '<script>togglePlay();</script>';
            }
            $content .= '<div class="center" id="random_picture_content' . $block_id . '">';
            $content .= '<table id="random_picture_box"><tr><td class="details1">';
            $content .= $random_media->displayImage();
            $content .= '<br>';
            $content .= '<a href="' . $random_media->getHtmlUrl() . '"><b>' . $random_media->getFullName() . '</b></a><br>';
            foreach ($random_media->linkedIndividuals('OBJE') as $individual) {
                $content .= '<a href="' . $individual->getHtmlUrl() . '">' . I18N::translate('View this individual') . ' — ' . $individual->getFullName() . '</a><br>';
            }
            foreach ($random_media->linkedFamilies('OBJE') as $family) {
                $content .= '<a href="' . $family->getHtmlUrl() . '">' . I18N::translate('View this family') . ' — ' . $family->getFullName() . '</a><br>';
            }
            foreach ($random_media->linkedSources('OBJE') as $source) {
                $content .= '<a href="' . $source->getHtmlUrl() . '">' . I18N::translate('View this source') . ' — ' . $source->getFullName() . '</a><br>';
            }
            $content .= '<br><div class="indent">';
            $content .= FunctionsPrint::printFactNotes($random_media->getGedcom(), "1", false);
            $content .= '</div>';
            $content .= '</td></tr></table>';
            $content .= '</div>';
            // random_picture_content
            $content .= '</div>';
            // random_picture_container
        } else {
            $content = I18N::translate('This family tree has no images to display.');
        }
        if ($template) {
            return Theme::theme()->formatBlock($id, $title, $class, $content);
        } else {
            return $content;
        }
    }
Exemple #27
0
$linked_sour = $controller->record->linkedSources('OBJE');
$linked_repo = $controller->record->linkedRepositories('OBJE');
// Invalid GEDCOM - you cannot link a REPO to an OBJE
$linked_note = $controller->record->linkedNotes('OBJE');
// Invalid GEDCOM - you cannot link a NOTE to an OBJE
echo '<div id="media-details">';
echo '<h2>', $controller->record->getFullName(), ' ', $controller->record->getAddName(), '</h2>';
echo '<div id="media-tabs">';
echo '<div id="media-edit">';
echo '<table class="facts_table">
			<tr>
				<td align="center" width="150">';
// When we have a pending edit, $controller->record shows the *old* data.
// As a temporary kludge, fetch a "normal" version of the record - which includes pending changes
// Perhaps check both, and use RED/BLUE boxes.
$tmp = Media::getInstance($controller->record->getXref(), $WT_TREE);
echo $tmp->displayImage();
if (!$tmp->isExternal()) {
    if ($tmp->fileExists('main')) {
        if ($controller->record->getTree()->getPreference('SHOW_MEDIA_DOWNLOAD')) {
            echo '<p><a href="' . $tmp->getHtmlUrlDirect('main', true) . '">' . I18N::translate('Download file') . '</a></p>';
        }
    } else {
        echo '<p class="ui-state-error">' . I18N::translate('The file “%s” does not exist.', $tmp->getFilename()) . '</p>';
    }
}
echo '</td>
				<td valign="top">
					<table width="100%">
						<tr>
							<td>
Exemple #28
0
 /**
  * Find media objects linked to this record.
  *
  * @param string $link
  *
  * @return Media[]
  */
 public function linkedMedia($link)
 {
     $rows = Database::prepare("SELECT m_id AS xref, m_gedcom AS gedcom" . " FROM `##media`" . " JOIN `##link` ON m_file = l_file AND m_id = l_from" . " WHERE m_file = :tree_id AND l_type = :link AND l_to = :xref" . " ORDER BY m_titl COLLATE :collation")->execute(array('tree_id' => $this->tree->getTreeId(), 'link' => $link, 'xref' => $this->xref, 'collation' => I18N::collation()))->fetchAll();
     $list = array();
     foreach ($rows as $row) {
         $record = Media::getInstance($row->xref, $this->tree, $row->gedcom);
         if ($record->canShowName()) {
             $list[] = $record;
         }
     }
     return $list;
 }
 /**
  * Edit menu items used in media list
  *
  * @param Media $mediaobject
  *
  * @return string
  */
 public static function getMediaListMenu(Media $mediaobject)
 {
     $html = '';
     $menu = new Menu(I18N::translate('Edit details'), '#', 'lb-image_edit', array('onclick' => 'return window.open("addmedia.php?action=editmedia&pid=' . $mediaobject->getXref() . '", "_blank", edit_window_specs);'));
     $html .= '<ul class="makeMenu lb-menu">' . $menu->getMenuAsList() . '</ul>';
     $menu = new Menu(I18N::translate('Manage links'), '#', 'lb-image_link', array('onclick' => 'return false;'), array(new Menu(I18N::translate('Link this media object to an individual'), '#', '', array('onclick' => 'return ilinkitem("' . $mediaobject->getXref() . '","person");')), new Menu(I18N::translate('Link this media object to a family'), '#', '', array('onclick' => 'return ilinkitem("' . $mediaobject->getXref() . '","family");')), new Menu(I18N::translate('Link this media object to a source'), '#', '', array('onclick' => 'return ilinkitem("' . $mediaobject->getXref() . '","source");'))));
     $html .= '<ul class="makeMenu lb-menu">' . $menu->getMenuAsList() . '</ul>';
     $menu = new Menu(I18N::translate('View details'), $mediaobject->getHtmlUrl(), 'lb-image_view');
     $html .= '<ul class="makeMenu lb-menu">' . $menu->getMenuAsList() . '</ul>';
     return '<div class="lightbox-menu">' . $html . '</div>';
 }
 /**
  * Check if thumbnails from cache should be recreated
  *
  * @param type $mediaobject
  * @return string filename
  */
 private function getThumbnail(Media $mediaobject)
 {
     $cache_dir = $this->cacheDir();
     if (!file_exists($cache_dir)) {
         File::mkdir($cache_dir);
     }
     if (file_exists($mediaobject->getServerFilename())) {
         $cache_filename = $this->cacheFileName($mediaobject);
         if (!is_file($cache_filename)) {
             if ($this->options('resize_thumbs')) {
                 $thumbnail = $this->fancyThumb($mediaobject);
                 $mimetype = $mediaobject->mimeType();
                 if ($mimetype === 'image/jpeg') {
                     imagejpeg($thumbnail, $cache_filename);
                 } elseif ($mimetype === 'image/png') {
                     imagepng($thumbnail, $cache_filename);
                 } else {
                     return;
                 }
             } else {
                 // if we are using the original webtrees thumbnails, copy them to the ftv_cache folder
                 // so we can cache them either and output them in the same way we would output the fancy thumbnail.
                 try {
                     copy($mediaobject->getServerFilename('thumb'), $cache_filename);
                 } catch (Exception $ex) {
                     // something went wrong while copying the default webtrees image to the ftv cache folder
                     // there is a fallback in the function printThumbnail(): output $mediaobject->displayImage();
                 }
             }
         }
         return $cache_filename;
     }
 }