$v) {
if (!preg_match_recursive($regex, $v)) {
return false;
}
}
return true;
} else {
// Neither scalar nor array. Object?
return false;
}
}
}
function trim_recursive($var) {
if (is_scalar($var)) {
return trim($var);
} else {
if (is_array($var)) {
foreach ($var as $k=>$v) {
$var[$k]=trim_recursive($v);
}
return $var;
} else {
// Neither scalar nor array. Object?
return $var;
}
}
}
// Convert a file upload PHP error code into user-friendly text
function file_upload_error_text($error_code) {
switch ($error_code) {
case UPLOAD_ERR_OK:
return i18n::translate('File successfully uploaded');
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
return i18n::translate('Uploaded file exceeds the allowed size');
case UPLOAD_ERR_PARTIAL:
return i18n::translate('File was only partially uploaded, please try again');
case UPLOAD_ERR_NO_FILE:
return i18n::translate('No file was received. Please upload again.');
case UPLOAD_ERR_NO_TMP_DIR:
return i18n::translate('Missing PHP temporary directory');
case UPLOAD_ERR_CANT_WRITE:
return i18n::translate('PHP failed to write to disk');
case UPLOAD_ERR_EXTENSION:
return i18n::translate('PHP blocked file by extension');
}
}
function load_gedcom_settings($ged_id=WT_GED_ID) {
// Load the configuration settings into global scope
// TODO: some of these are used infrequently - just load them when we need them
global $ABBREVIATE_CHART_LABELS; $ABBREVIATE_CHART_LABELS =get_gedcom_setting($ged_id, 'ABBREVIATE_CHART_LABELS');
global $ADVANCED_NAME_FACTS; $ADVANCED_NAME_FACTS =get_gedcom_setting($ged_id, 'ADVANCED_NAME_FACTS');
global $ADVANCED_PLAC_FACTS; $ADVANCED_PLAC_FACTS =get_gedcom_setting($ged_id, 'ADVANCED_PLAC_FACTS');
global $ALLOW_EDIT_GEDCOM; $ALLOW_EDIT_GEDCOM =get_gedcom_setting($ged_id, 'ALLOW_EDIT_GEDCOM');
global $ALLOW_THEME_DROPDOWN; $ALLOW_THEME_DROPDOWN =get_gedcom_setting($ged_id, 'ALLOW_THEME_DROPDOWN');
global $CALENDAR_FORMAT; $CALENDAR_FORMAT =get_gedcom_setting($ged_id, 'CALENDAR_FORMAT');
global $CHART_BOX_TAGS; $CHART_BOX_TAGS =get_gedcom_setting($ged_id, 'CHART_BOX_TAGS');
global $CHECK_MARRIAGE_RELATIONS; $CHECK_MARRIAGE_RELATIONS =get_gedcom_setting($ged_id, 'CHECK_MARRIAGE_RELATIONS');
global $COMMON_NAMES_ADD; $COMMON_NAMES_ADD =get_gedcom_setting($ged_id, 'COMMON_NAMES_ADD');
global $COMMON_NAMES_REMOVE; $COMMON_NAMES_REMOVE =get_gedcom_setting($ged_id, 'COMMON_NAMES_REMOVE');
global $COMMON_NAMES_THRESHOLD; $COMMON_NAMES_THRESHOLD =get_gedcom_setting($ged_id, 'COMMON_NAMES_THRESHOLD');
global $CONTACT_USER_ID; $CONTACT_USER_ID =get_gedcom_setting($ged_id, 'CONTACT_USER_ID');
global $DAYS_TO_SHOW_LIMIT; $DAYS_TO_SHOW_LIMIT =get_gedcom_setting($ged_id, 'DAYS_TO_SHOW_LIMIT');
global $DEFAULT_PEDIGREE_GENERATIONS; $DEFAULT_PEDIGREE_GENERATIONS =get_gedcom_setting($ged_id, 'DEFAULT_PEDIGREE_GENERATIONS');
global $DISPLAY_JEWISH_GERESHAYIM; $DISPLAY_JEWISH_GERESHAYIM =get_gedcom_setting($ged_id, 'DISPLAY_JEWISH_GERESHAYIM');
global $DISPLAY_JEWISH_THOUSANDS; $DISPLAY_JEWISH_THOUSANDS =get_gedcom_setting($ged_id, 'DISPLAY_JEWISH_THOUSANDS');
global $EDIT_AUTOCLOSE; $EDIT_AUTOCLOSE =get_gedcom_setting($ged_id, 'EDIT_AUTOCLOSE');
global $ENABLE_AUTOCOMPLETE; $ENABLE_AUTOCOMPLETE =get_gedcom_setting($ged_id, 'ENABLE_AUTOCOMPLETE');
global $ENABLE_RSS; $ENABLE_RSS =get_gedcom_setting($ged_id, 'ENABLE_RSS');
global $EXPAND_NOTES; $EXPAND_NOTES =get_gedcom_setting($ged_id, 'EXPAND_NOTES');
global $EXPAND_RELATIVES_EVENTS; $EXPAND_RELATIVES_EVENTS =get_gedcom_setting($ged_id, 'EXPAND_RELATIVES_EVENTS');
global $EXPAND_SOURCES; $EXPAND_SOURCES =get_gedcom_setting($ged_id, 'EXPAND_SOURCES');
global $FAM_FACTS_ADD; $FAM_FACTS_ADD =get_gedcom_setting($ged_id, 'FAM_FACTS_ADD');
global $FAM_FACTS_QUICK; $FAM_FACTS_QUICK =get_gedcom_setting($ged_id, 'FAM_FACTS_QUICK');
global $FAM_FACTS_UNIQUE; $FAM_FACTS_UNIQUE =get_gedcom_setting($ged_id, 'FAM_FACTS_UNIQUE');
global $FAM_ID_PREFIX; $FAM_ID_PREFIX =get_gedcom_setting($ged_id, 'FAM_ID_PREFIX');
global $FAVICON; $FAVICON =get_gedcom_setting($ged_id, 'FAVICON');
global $FULL_SOURCES; $FULL_SOURCES =get_gedcom_setting($ged_id, 'FULL_SOURCES');
global $GEDCOM_DEFAULT_TAB; $GEDCOM_DEFAULT_TAB =get_gedcom_setting($ged_id, 'GEDCOM_DEFAULT_TAB');
global $GEDCOM_ID_PREFIX; $GEDCOM_ID_PREFIX =get_gedcom_setting($ged_id, 'GEDCOM_ID_PREFIX');
global $GENERATE_UIDS; $GENERATE_UIDS =get_gedcom_setting($ged_id, 'GENERATE_UIDS');
global $HIDE_GEDCOM_ERRORS; $HIDE_GEDCOM_ERRORS =get_gedcom_setting($ged_id, 'HIDE_GEDCOM_ERRORS');
global $HIDE_LIVE_PEOPLE; $HIDE_LIVE_PEOPLE =get_gedcom_setting($ged_id, 'HIDE_LIVE_PEOPLE');
global $HOME_SITE_TEXT; $HOME_SITE_TEXT =get_gedcom_setting($ged_id, 'HOME_SITE_TEXT');
global $HOME_SITE_URL; $HOME_SITE_URL =get_gedcom_setting($ged_id, 'HOME_SITE_URL');
global $INDI_FACTS_ADD; $INDI_FACTS_ADD =get_gedcom_setting($ged_id, 'INDI_FACTS_ADD');
global $INDI_FACTS_QUICK; $INDI_FACTS_QUICK =get_gedcom_setting($ged_id, 'INDI_FACTS_QUICK');
global $INDI_FACTS_UNIQUE; $INDI_FACTS_UNIQUE =get_gedcom_setting($ged_id, 'INDI_FACTS_UNIQUE');
global $LANGUAGE; $LANGUAGE =get_gedcom_setting($ged_id, 'LANGUAGE');
global $LINK_ICONS; $LINK_ICONS =get_gedcom_setting($ged_id, 'LINK_ICONS');
global $MAX_ALIVE_AGE; $MAX_ALIVE_AGE =get_gedcom_setting($ged_id, 'MAX_ALIVE_AGE');
global $MAX_DESCENDANCY_GENERATIONS; $MAX_DESCENDANCY_GENERATIONS =get_gedcom_setting($ged_id, 'MAX_DESCENDANCY_GENERATIONS');
global $MAX_PEDIGREE_GENERATIONS; $MAX_PEDIGREE_GENERATIONS =get_gedcom_setting($ged_id, 'MAX_PEDIGREE_GENERATIONS');
global $MAX_RELATION_PATH_LENGTH; $MAX_RELATION_PATH_LENGTH =get_gedcom_setting($ged_id, 'MAX_RELATION_PATH_LENGTH');
global $MEDIA_DIRECTORY; $MEDIA_DIRECTORY =get_gedcom_setting($ged_id, 'MEDIA_DIRECTORY');
global $MEDIA_DIRECTORY_LEVELS; $MEDIA_DIRECTORY_LEVELS =get_gedcom_setting($ged_id, 'MEDIA_DIRECTORY_LEVELS');
global $MEDIA_EXTERNAL; $MEDIA_EXTERNAL =get_gedcom_setting($ged_id, 'MEDIA_EXTERNAL');
global $MEDIA_FIREWALL_ROOTDIR; $MEDIA_FIREWALL_ROOTDIR =get_gedcom_setting($ged_id, 'MEDIA_FIREWALL_ROOTDIR');
global $MEDIA_FIREWALL_THUMBS; $MEDIA_FIREWALL_THUMBS =get_gedcom_setting($ged_id, 'MEDIA_FIREWALL_THUMBS');
global $MEDIA_ID_PREFIX; $MEDIA_ID_PREFIX =get_gedcom_setting($ged_id, 'MEDIA_ID_PREFIX');
global $META_DESCRIPTION; $META_DESCRIPTION =get_gedcom_setting($ged_id, 'META_DESCRIPTION');
global $META_ROBOTS; $META_ROBOTS =get_gedcom_setting($ged_id, 'META_ROBOTS');
global $META_TITLE; $META_TITLE =get_gedcom_setting($ged_id, 'META_TITLE');
global $MULTI_MEDIA; $MULTI_MEDIA =get_gedcom_setting($ged_id, 'MULTI_MEDIA');
global $NOTE_FACTS_ADD; $NOTE_FACTS_ADD =get_gedcom_setting($ged_id, 'NOTE_FACTS_ADD');
global $NOTE_FACTS_QUICK; $NOTE_FACTS_QUICK =get_gedcom_setting($ged_id, 'NOTE_FACTS_QUICK');
global $NOTE_FACTS_UNIQUE; $NOTE_FACTS_UNIQUE =get_gedcom_setting($ged_id, 'NOTE_FACTS_UNIQUE');
global $NOTE_ID_PREFIX; $NOTE_ID_PREFIX =get_gedcom_setting($ged_id, 'NOTE_ID_PREFIX');
global $NO_UPDATE_CHAN; $NO_UPDATE_CHAN =get_gedcom_setting($ged_id, 'NO_UPDATE_CHAN');
global $PAGE_AFTER_LOGIN; $PAGE_AFTER_LOGIN =get_gedcom_setting($ged_id, 'PAGE_AFTER_LOGIN');
global $PEDIGREE_FULL_DETAILS; $PEDIGREE_FULL_DETAILS =get_gedcom_setting($ged_id, 'PEDIGREE_FULL_DETAILS');
global $PEDIGREE_LAYOUT; $PEDIGREE_LAYOUT =get_gedcom_setting($ged_id, 'PEDIGREE_LAYOUT');
global $PEDIGREE_ROOT_ID; $PEDIGREE_ROOT_ID =get_gedcom_setting($ged_id, 'PEDIGREE_ROOT_ID');
global $PEDIGREE_SHOW_GENDER; $PEDIGREE_SHOW_GENDER =get_gedcom_setting($ged_id, 'PEDIGREE_SHOW_GENDER');
global $POSTAL_CODE; $POSTAL_CODE =get_gedcom_setting($ged_id, 'POSTAL_CODE');
global $PREFER_LEVEL2_SOURCES; $PREFER_LEVEL2_SOURCES =get_gedcom_setting($ged_id, 'PREFER_LEVEL2_SOURCES');
global $PRIVACY_BY_YEAR; $PRIVACY_BY_YEAR =get_gedcom_setting($ged_id, 'PRIVACY_BY_YEAR');
global $QUICK_REQUIRED_FACTS; $QUICK_REQUIRED_FACTS =get_gedcom_setting($ged_id, 'QUICK_REQUIRED_FACTS');
global $QUICK_REQUIRED_FAMFACTS; $QUICK_REQUIRED_FAMFACTS =get_gedcom_setting($ged_id, 'QUICK_REQUIRED_FAMFACTS');
global $REPO_FACTS_ADD; $REPO_FACTS_ADD =get_gedcom_setting($ged_id, 'REPO_FACTS_ADD');
global $REPO_FACTS_QUICK; $REPO_FACTS_QUICK =get_gedcom_setting($ged_id, 'REPO_FACTS_QUICK');
global $REPO_FACTS_UNIQUE; $REPO_FACTS_UNIQUE =get_gedcom_setting($ged_id, 'REPO_FACTS_UNIQUE');
global $REPO_ID_PREFIX; $REPO_ID_PREFIX =get_gedcom_setting($ged_id, 'REPO_ID_PREFIX');
global $REQUIRE_AUTHENTICATION; $REQUIRE_AUTHENTICATION =get_gedcom_setting($ged_id, 'REQUIRE_AUTHENTICATION');
global $RSS_FORMAT; $RSS_FORMAT =get_gedcom_setting($ged_id, 'RSS_FORMAT');
global $SAVE_WATERMARK_IMAGE; $SAVE_WATERMARK_IMAGE =get_gedcom_setting($ged_id, 'SAVE_WATERMARK_IMAGE');
global $SAVE_WATERMARK_THUMB; $SAVE_WATERMARK_THUMB =get_gedcom_setting($ged_id, 'SAVE_WATERMARK_THUMB');
global $SEARCH_FACTS_DEFAULT; $SEARCH_FACTS_DEFAULT =get_gedcom_setting($ged_id, 'SEARCH_FACTS_DEFAULT');
global $SHOW_AGE_DIFF; $SHOW_AGE_DIFF =get_gedcom_setting($ged_id, 'SHOW_AGE_DIFF');
global $SHOW_COUNTER; $SHOW_COUNTER =get_gedcom_setting($ged_id, 'SHOW_COUNTER');
global $SHOW_DEAD_PEOPLE; $SHOW_DEAD_PEOPLE =get_gedcom_setting($ged_id, 'SHOW_DEAD_PEOPLE');
global $SHOW_EMPTY_BOXES; $SHOW_EMPTY_BOXES =get_gedcom_setting($ged_id, 'SHOW_EMPTY_BOXES');
global $SHOW_FACT_ICONS; $SHOW_FACT_ICONS =get_gedcom_setting($ged_id, 'SHOW_FACT_ICONS');
global $SHOW_GEDCOM_RECORD; $SHOW_GEDCOM_RECORD =get_gedcom_setting($ged_id, 'SHOW_GEDCOM_RECORD');
global $SHOW_HIGHLIGHT_IMAGES; $SHOW_HIGHLIGHT_IMAGES =get_gedcom_setting($ged_id, 'SHOW_HIGHLIGHT_IMAGES');
global $SHOW_LAST_CHANGE; $SHOW_LAST_CHANGE =get_gedcom_setting($ged_id, 'SHOW_LAST_CHANGE');
global $SHOW_LDS_AT_GLANCE; $SHOW_LDS_AT_GLANCE =get_gedcom_setting($ged_id, 'SHOW_LDS_AT_GLANCE');
global $SHOW_LEVEL2_NOTES; $SHOW_LEVEL2_NOTES =get_gedcom_setting($ged_id, 'SHOW_LEVEL2_NOTES');
global $SHOW_LIST_PLACES; $SHOW_LIST_PLACES =get_gedcom_setting($ged_id, 'SHOW_LIST_PLACES');
global $SHOW_LIVING_NAMES; $SHOW_LIVING_NAMES =get_gedcom_setting($ged_id, 'SHOW_LIVING_NAMES');
global $SHOW_MARRIED_NAMES; $SHOW_MARRIED_NAMES =get_gedcom_setting($ged_id, 'SHOW_MARRIED_NAMES');
global $SHOW_MEDIA_DOWNLOAD; $SHOW_MEDIA_DOWNLOAD =get_gedcom_setting($ged_id, 'SHOW_MEDIA_DOWNLOAD');
global $SHOW_MEDIA_FILENAME; $SHOW_MEDIA_FILENAME =get_gedcom_setting($ged_id, 'SHOW_MEDIA_FILENAME');
global $SHOW_MULTISITE_SEARCH; $SHOW_MULTISITE_SEARCH =get_gedcom_setting($ged_id, 'SHOW_MULTISITE_SEARCH');
global $SHOW_NO_WATERMARK; $SHOW_NO_WATERMARK =get_gedcom_setting($ged_id, 'SHOW_NO_WATERMARK');
global $SHOW_PARENTS_AGE; $SHOW_PARENTS_AGE =get_gedcom_setting($ged_id, 'SHOW_PARENTS_AGE');
global $SHOW_PEDIGREE_PLACES; $SHOW_PEDIGREE_PLACES =get_gedcom_setting($ged_id, 'SHOW_PEDIGREE_PLACES');
global $SHOW_PRIVATE_RELATIONSHIPS; $SHOW_PRIVATE_RELATIONSHIPS =get_gedcom_setting($ged_id, 'SHOW_PRIVATE_RELATIONSHIPS');
global $SHOW_REGISTER_CAUTION; $SHOW_REGISTER_CAUTION =get_gedcom_setting($ged_id, 'SHOW_REGISTER_CAUTION');
global $SHOW_RELATIVES_EVENTS; $SHOW_RELATIVES_EVENTS =get_gedcom_setting($ged_id, 'SHOW_RELATIVES_EVENTS');
global $SHOW_SPIDER_TAGLINE; $SHOW_SPIDER_TAGLINE =get_gedcom_setting($ged_id, 'SHOW_SPIDER_TAGLINE');
global $SHOW_STATS; $SHOW_STATS =get_gedcom_setting($ged_id, 'SHOW_STATS');
global $SOURCE_ID_PREFIX; $SOURCE_ID_PREFIX =get_gedcom_setting($ged_id, 'SOURCE_ID_PREFIX');
global $SOUR_FACTS_ADD; $SOUR_FACTS_ADD =get_gedcom_setting($ged_id, 'SOUR_FACTS_ADD');
global $SOUR_FACTS_QUICK; $SOUR_FACTS_QUICK =get_gedcom_setting($ged_id, 'SOUR_FACTS_QUICK');
global $SOUR_FACTS_UNIQUE; $SOUR_FACTS_UNIQUE =get_gedcom_setting($ged_id, 'SOUR_FACTS_UNIQUE');
global $SPLIT_PLACES; $SPLIT_PLACES =get_gedcom_setting($ged_id, 'SPLIT_PLACES');
global $SURNAME_LIST_STYLE; $SURNAME_LIST_STYLE =get_gedcom_setting($ged_id, 'SURNAME_LIST_STYLE');
global $THEME_DIR; $THEME_DIR =get_gedcom_setting($ged_id, 'THEME_DIR');
global $THUMBNAIL_WIDTH; $THUMBNAIL_WIDTH =get_gedcom_setting($ged_id, 'THUMBNAIL_WIDTH');
global $UNDERLINE_NAME_QUOTES; $UNDERLINE_NAME_QUOTES =get_gedcom_setting($ged_id, 'UNDERLINE_NAME_QUOTES');
global $USE_GEONAMES; $USE_GEONAMES =get_gedcom_setting($ged_id, 'USE_GEONAMES');
global $USE_MEDIA_FIREWALL; $USE_MEDIA_FIREWALL =get_gedcom_setting($ged_id, 'USE_MEDIA_FIREWALL');
global $USE_MEDIA_VIEWER; $USE_MEDIA_VIEWER =get_gedcom_setting($ged_id, 'USE_MEDIA_VIEWER');
global $USE_RELATIONSHIP_PRIVACY; $USE_RELATIONSHIP_PRIVACY =get_gedcom_setting($ged_id, 'USE_RELATIONSHIP_PRIVACY');
global $USE_RIN; $USE_RIN =get_gedcom_setting($ged_id, 'USE_RIN');
global $USE_SILHOUETTE; $USE_SILHOUETTE =get_gedcom_setting($ged_id, 'USE_SILHOUETTE');
global $USE_THUMBS_MAIN; $USE_THUMBS_MAIN =get_gedcom_setting($ged_id, 'USE_THUMBS_MAIN');
global $WATERMARK_THUMB; $WATERMARK_THUMB =get_gedcom_setting($ged_id, 'WATERMARK_THUMB');
global $WEBMASTER_USER_ID; $WEBMASTER_USER_ID =get_gedcom_setting($ged_id, 'WEBMASTER_USER_ID');
global $WEBTREES_EMAIL; $WEBTREES_EMAIL =get_gedcom_setting($ged_id, 'WEBTREES_EMAIL');
global $WELCOME_TEXT_AUTH_MODE; $WELCOME_TEXT_AUTH_MODE =get_gedcom_setting($ged_id, 'WELCOME_TEXT_AUTH_MODE');
global $WELCOME_TEXT_AUTH_MODE_4; $WELCOME_TEXT_AUTH_MODE_4 =get_gedcom_setting($ged_id, 'WELCOME_TEXT_AUTH_MODE_4');
global $WELCOME_TEXT_CUST_HEAD; $WELCOME_TEXT_CUST_HEAD =get_gedcom_setting($ged_id, 'WELCOME_TEXT_CUST_HEAD');
global $WORD_WRAPPED_NOTES; $WORD_WRAPPED_NOTES =get_gedcom_setting($ged_id, 'WORD_WRAPPED_NOTES');
global $ZOOM_BOXES; $ZOOM_BOXES =get_gedcom_setting($ged_id, 'ZOOM_BOXES');
global $person_privacy; $person_privacy=array();
global $person_facts; $person_facts =array();
global $global_facts; $global_facts =array();
$rows=WT_DB::prepare(
"SELECT SQL_CACHE xref, tag_type, CASE resn WHEN 'none' THEN ? WHEN 'privacy' THEN ? WHEN 'confidential' THEN ? WHEN 'hidden' THEN ? END AS resn FROM `##default_resn` WHERE gedcom_id=?"
)->execute(array(WT_PRIV_HIDE, WT_PRIV_NONE, WT_PRIV_USER, WT_PRIV_PUBLIC, $ged_id))->fetchAll();
foreach ($rows as $row) {
if ($row->xref!==null) {
if ($row->tag_type!==null) {
$person_facts[$row->xref][$row->tag_type]=(int)$row->resn;
} else {
$person_privacy[$row->xref]=(int)$row->resn;
}
} else {
$global_facts[$row->tag_type]=(int)$row->resn;
}
}
}
/**
* Webtrees Error Handling function
*
* This function will be called by PHP whenever an error occurs. The error handling
* is set in the session.php
* @see http://us2.php.net/manual/en/function.set-error-handler.php
*/
function wt_error_handler($errno, $errstr, $errfile, $errline) {
if ((error_reporting() > 0)&&($errno<2048)) {
if (WT_ERROR_LEVEL==0) {
return;
}
if (stristr($errstr, "by reference")==true) {
return;
}
$fmt_msg="\n
ERROR {$errno}: {$errstr}
\n";
$log_msg="ERROR {$errno}: {$errstr};";
// Although debug_backtrace should always exist in PHP5, without this check, PHP sometimes crashes.
// Possibly calling it generates an error, which causes infinite recursion??
if ($errno<16 && function_exists("debug_backtrace") && strstr($errstr, "headers already sent by")===false) {
$backtrace=debug_backtrace();
$num=count($backtrace);
if (WT_ERROR_LEVEL==1) {
$num=1;
}
for ($i=0; $i<$num; $i++) {
if ($i==0) {
$fmt_msg.="0 Error occurred on ";
$log_msg.="\n0 Error occurred on ";
} else {
$fmt_msg.="{$i} called from ";
$log_msg.="\n{$i} called from ";
}
if (isset($backtrace[$i]["line"]) && isset($backtrace[$i]["file"])) {
$fmt_msg.="line {$backtrace[$i]['line']} of file ".basename($backtrace[$i]['file'])."";
$log_msg.="line {$backtrace[$i]['line']} of file ".basename($backtrace[$i]['file']);
}
if ($i<$num-1) {
$fmt_msg.=" in function ".$backtrace[$i+1]['function']."";
$log_msg.=" in function ".$backtrace[$i+1]['function'];
}
$fmt_msg.="
\n";
}
}
echo $fmt_msg;
if (function_exists('AddToLog')) {
AddToLog($log_msg, 'error');
}
if ($errno==1) {
die();
}
}
return false;
}
// ************************************************* START OF GEDCOM FUNCTIONS ********************************* //
/**
* Get first tag in GEDCOM sub-record
*
* This routine uses function get_sub_record to retrieve the specified sub-record
* and then returns the first tag.
*
*/
function get_first_tag($level, $tag, $gedrec, $num=1) {
$temp = get_sub_record($level, $level." ".$tag, $gedrec, $num)."\n";
$temp = str_replace("\r\n", "\n", $temp);
$length = strpos($temp, "\n");
if ($length===false) {
$length = strlen($temp);
}
return substr($temp, 2, $length-2);
}
/**
* get a gedcom subrecord
*
* searches a gedcom record and returns a subrecord of it. A subrecord is defined starting at a
* line with level N and all subsequent lines greater than N until the next N level is reached.
* For example, the following is a BIRT subrecord:
* 1 BIRT
* 2 DATE 1 JAN 1900
* 2 PLAC Phoenix, Maricopa, Arizona
* The following example is the DATE subrecord of the above BIRT subrecord:
* 2 DATE 1 JAN 1900
* @author John Finlay (yalnifj)
* @author Roland Dalmulder (roland-d)
* @param int $level the N level of the subrecord to get
* @param string $tag a gedcom tag or string to search for in the record (ie 1 BIRT or 2 DATE)
* @param string $gedrec the parent gedcom record to search in
* @param int $num this allows you to specify which matching $tag to get. Oftentimes a
* gedcom record will have more that 1 of the same type of subrecord. An individual may have
* multiple events for example. Passing $num=1 would get the first 1. Passing $num=2 would get the
* second one, etc.
* @return string the subrecord that was found or an empty string "" if not found.
*/
function get_sub_record($level, $tag, $gedrec, $num=1) {
if (empty($gedrec)) {
return "";
}
// -- adding \n before and after gedrec
$gedrec = "\n".$gedrec."\n";
$pos1=0;
$subrec = "";
$tag = trim($tag);
$searchTarget = "~[\r\n]".$tag."[\s]~";
$ct = preg_match_all($searchTarget, $gedrec, $match, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
if ($ct==0) {
$tag = preg_replace('/(\w+)/', "_$1", $tag);
$ct = preg_match_all($searchTarget, $gedrec, $match, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
if ($ct==0) {
return "";
}
}
if ($ct<$num) {
return "";
}
$pos1 = $match[$num-1][0][1];
$pos2 = strpos($gedrec, "\n$level", $pos1+1);
if (!$pos2) {
$pos2 = strpos($gedrec, "\n1", $pos1+1);
}
if (!$pos2) {
$pos2 = strpos($gedrec, "\nWT_", $pos1+1); // WT_SPOUSE, WT_FAMILY_ID ...
}
if (!$pos2) {
return ltrim(substr($gedrec, $pos1));
}
$subrec = substr($gedrec, $pos1, $pos2-$pos1);
return ltrim($subrec);
}
/**
* find all of the level 1 subrecords of the given record
* @param string $gedrec the gedcom record to get the subrecords from
* @param string $ignore a list of tags to ignore
* @param boolean $families whether to include any records from the family
* @param boolean $sort whether or not to sort the record by date
* @param boolean $ApplyPriv whether to apply privacy right now or later
* @return array an array of the raw subrecords to return
*/
function get_all_subrecords($gedrec, $ignore="", $families=true, $ApplyPriv=true) {
global $GEDCOM;
$ged_id=get_id_from_gedcom($GEDCOM);
$repeats = array();
$id = "";
$gt = preg_match('/0 @('.WT_REGEX_XREF.')@/', $gedrec, $gmatch);
if ($gt > 0) {
$id = $gmatch[1];
}
$hasResn = strstr($gedrec, " RESN ");
$prev_tags = array();
$ct = preg_match_all('/\n1 ('.WT_REGEX_TAG.')(.*)/', $gedrec, $match, PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
for ($i=0; $i<$ct; $i++) {
$fact = trim($match[$i][1][0]);
$pos1 = $match[$i][0][1];
if ($i<$ct-1) {
$pos2 = $match[$i+1][0][1];
} else {
$pos2 = strlen($gedrec);
}
if (empty($ignore) || strpos($ignore, $fact)===false) {
if (!$ApplyPriv || (showFact($fact, $id))) {
if (isset($prev_tags[$fact])) {
$prev_tags[$fact]++;
} else {
$prev_tags[$fact] = 1;
}
$subrec = substr($gedrec, $pos1, $pos2-$pos1);
if (!$ApplyPriv || !$hasResn || !FactViewRestricted($id, $subrec)) {
if ($fact=="EVEN") {
$tt = preg_match("/2 TYPE (.*)/", $subrec, $tmatch);
if ($tt>0) {
$type = trim($tmatch[1]);
if (!$ApplyPriv || (showFact($type, $id))) {
$repeats[] = trim($subrec)."\n";
}
} else
$repeats[] = trim($subrec)."\n";
} else {
$repeats[] = trim($subrec)."\n";
}
}
}
}
}
//-- look for any records in FAMS records
if ($families) {
$ft = preg_match_all('/\n1 FAMS @('.WT_REGEX_XREF.')@/', $gedrec, $fmatch, PREG_SET_ORDER);
for ($f=0; $f<$ft; $f++) {
$famid = $fmatch[$f][1];
$famrec = find_family_record($fmatch[$f][1], $ged_id);
$parents = find_parents_in_record($famrec);
if ($id==$parents["HUSB"]) {
$spid = $parents["WIFE"];
} else {
$spid = $parents["HUSB"];
}
$prev_tags = array();
$ct = preg_match_all('/\n1 ('.WT_REGEX_TAG.')(.*)/', $famrec, $match, PREG_SET_ORDER);
for ($i=0; $i<$ct; $i++) {
$fact = trim($match[$i][1]);
if (empty($ignore) || strpos($ignore, $fact)===false) {
if (!$ApplyPriv || (showFact($fact, $id))) {
if (isset($prev_tags[$fact])) {
$prev_tags[$fact]++;
} else {
$prev_tags[$fact] = 1;
}
$subrec = get_sub_record(1, "1 $fact", $famrec, $prev_tags[$fact]);
$subrec .= "\n2 _PGVS @$spid@\n2 _PGVFS @$famid@\n";
if ($fact=="EVEN") {
$ct = preg_match("/2 TYPE (.*)/", $subrec, $tmatch);
if ($ct>0) {
$type = trim($tmatch[1]);
if (!$ApplyPriv or (showFact($type, $id))) {
$repeats[] = trim($subrec)."\n";
}
} else {
$repeats[] = trim($subrec)."\n";
}
} else {
$repeats[] = trim($subrec)."\n";
}
}
}
}
}
}
return $repeats;
}
/**
* get gedcom tag value
*
* returns the value of a gedcom tag from the given gedcom record
* @param string $tag The tag to find, use : to delineate subtags
* @param int $level The gedcom line level of the first tag to find, setting level to 0 will cause it to use 1+ the level of the incoming record
* @param string $gedrec The gedcom record to get the value from
* @param int $truncate Should the value be truncated to a certain number of characters
* @param boolean $convert Should data like dates be converted using the configuration settings
* @return string
*/
function get_gedcom_value($tag, $level, $gedrec, $truncate='', $convert=true) {
global $SHOW_PEDIGREE_PLACES, $GEDCOM;
$ged_id=get_id_from_gedcom($GEDCOM);
if (empty($gedrec)) {
return "";
}
$tags = explode(':', $tag);
$origlevel = $level;
if ($level==0) {
$level = $gedrec{0} + 1;
}
$subrec = $gedrec;
foreach ($tags as $indexval => $t) {
$lastsubrec = $subrec;
$subrec = get_sub_record($level, "$level $t", $subrec);
if (empty($subrec) && $origlevel==0) {
$level--;
$subrec = get_sub_record($level, "$level $t", $lastsubrec);
}
if (empty($subrec)) {
if ($t=="TITL") {
$subrec = get_sub_record($level, "$level ABBR", $lastsubrec);
if (!empty($subrec)) {
$t = "ABBR";
}
}
if (empty($subrec)) {
if ($level>0) {
$level--;
}
$subrec = get_sub_record($level, "@ $t", $gedrec);
if (empty($subrec)) {
return;
}
}
}
$level++;
}
$level--;
$ct = preg_match("/$level $t(.*)/", $subrec, $match);
if ($ct==0) {
$ct = preg_match("/$level @.+@ (.+)/", $subrec, $match);
}
if ($ct==0) {
$ct = preg_match("/@ $t (.+)/", $subrec, $match);
}
if ($ct > 0) {
$value = trim($match[1]);
$ct = preg_match("/@(.*)@/", $value, $match);
if (($ct > 0 ) && ($t!="DATE")) {
$oldsub = $subrec;
switch ($t) {
case 'HUSB':
case 'WIFE':
case 'CHIL':
$subrec = find_person_record($match[1], $ged_id);
break;
case 'FAMC':
case 'FAMS':
$subrec = find_family_record($match[1], $ged_id);
break;
case 'SOUR':
$subrec = find_source_record($match[1], $ged_id);
break;
case 'REPO':
$subrec = find_other_record($match[1], $ged_id);
break;
default:
$subrec = find_gedcom_record($match[1], $ged_id);
break;
}
if ($subrec) {
$value=$match[1];
$ct = preg_match("/0 @$match[1]@ $t (.+)/", $subrec, $match);
if ($ct>0) {
$value = $match[1];
$level = 0;
} else
$subrec = $oldsub;
} else
//-- set the value to the id without the @
$value = $match[1];
}
if ($level!=0 || $t!="NOTE") {
$value .= get_cont($level+1, $subrec);
}
$value = preg_replace("'\n'", "", $value);
$value = preg_replace("'
'", "\n", $value);
$value = trim($value);
//-- if it is a date value then convert the date
if ($convert && $t=="DATE") {
$g = new GedcomDate($value);
$value = $g->Display();
if (!empty($truncate)) {
if (utf8_strlen($value)>$truncate) {
$value = preg_replace("/\(.+\)/", "", $value);
//if (utf8_strlen($value)>$truncate) {
// $value = preg_replace_callback("/([a-zśź]+)/ui", create_function('$matches', 'return utf8_substr($matches[1], 0, 3);'), $value);
//}
}
}
} else
//-- if it is a place value then apply the pedigree place limit
if ($convert && $t=="PLAC") {
if ($SHOW_PEDIGREE_PLACES>0) {
$plevels = explode(',', $value);
$value = "";
for ($plevel=0; $plevel<$SHOW_PEDIGREE_PLACES; $plevel++) {
if (!empty($plevels[$plevel])) {
if ($plevel>0) {
$value .= ", ";
}
$value .= trim($plevels[$plevel]);
}
}
}
if (!empty($truncate)) {
if (strlen($value)>$truncate) {
$plevels = explode(',', $value);
$value = "";
for ($plevel=0; $plevel0) {
$value .= ", ";
}
$value .= trim($plevels[$plevel]);
} else
break;
}
}
}
}
} else
if ($convert && $t=="SEX") {
if ($value=="M") {
$value = utf8_substr(i18n::translate('Male'), 0, 1);
} elseif ($value=="F") {
$value = utf8_substr(i18n::translate('Female'), 0, 1);
} else {
$value = utf8_substr(i18n::translate('unknown'), 0, 1);
}
} else {
if (!empty($truncate)) {
if (strlen($value)>$truncate) {
$plevels = explode(' ', $value);
$value = "";
for ($plevel=0; $plevel0) {
$value .= " ";
}
$value .= trim($plevels[$plevel]);
} else
break;
}
}
}
}
}
return $value;
}
return "";
}
/**
* create CONT lines
*
* Break input GEDCOM subrecord into pieces not more than 255 chars long,
* with CONC and CONT lines as needed. Routine also pays attention to the
* word wrapped Notes option. Routine also avoids splitting UTF-8 encoded
* characters between lines.
*
* @param string $newline Input GEDCOM subrecord to be worked on
* @return string $newged Output string with all necessary CONC and CONT lines
*/
function breakConts($newline) {
global $WORD_WRAPPED_NOTES;
// Determine level number of CONC and CONT lines
$level = substr($newline, 0, 1);
$tag = substr($newline, 1, 6);
if ($tag!=" CONC " && $tag!=" CONT ") {
$level ++;
}
$newged = "";
$newlines = preg_split("/\r?\n/", rtrim(stripLRMRLM($newline)));
for ($k=0; $k0) {
$newlines[$k] = "{$level} CONT ".$newlines[$k];
}
$newged .= trim($newlines[$k])."\n";
}
return $newged;
}
/**
* get CONT lines
*
* get the N+1 CONT or CONC lines of a gedcom subrecord
* @param int $nlevel the level of the CONT lines to get
* @param string $nrec the gedcom subrecord to search in
* @return string a string with all CONT or CONC lines merged
*/
function get_cont($nlevel, $nrec, $tobr=true) {
global $WORD_WRAPPED_NOTES;
$text = "";
if ($tobr) {
$newline = "
";
} else {
$newline = "\n";
}
$subrecords = explode("\n", $nrec);
foreach ($subrecords as $thisSubrecord) {
if (substr($thisSubrecord, 0, 2)!=$nlevel." ") {
continue;
}
$subrecordType = substr($thisSubrecord, 2, 4);
if ($subrecordType=="CONT") {
$text .= $newline;
}
if ($subrecordType=="CONC" && $WORD_WRAPPED_NOTES) {
$text .= " ";
}
if ($subrecordType=="CONT" || $subrecordType=="CONC") {
$text .= rtrim(substr($thisSubrecord, 7));
}
}
return rtrim($text, " ");
}
/**
* find the parents in a family
*
* find and return a two element array containing the parents of the given family record
* @author John Finlay (yalnifj)
* @param string $famid the gedcom xref id for the family
* @return array returns a two element array with indexes HUSB and WIFE for the parent ids
*/
function find_parents($famid) {
$famrec = find_gedcom_record($famid, WT_GED_ID, WT_USER_CAN_EDIT);
if (empty($famrec)) {
return false;
}
return find_parents_in_record($famrec);
}
/**
* find the parents in a family record
*
* find and return a two element array containing the parents of the given family record
* @author John Finlay (yalnifj)
* @param string $famrec the gedcom record of the family to search in
* @return array returns a two element array with indexes HUSB and WIFE for the parent ids
*/
function find_parents_in_record($famrec) {
if (empty($famrec)) {
return false;
}
$parents = array();
$ct = preg_match('/1 HUSB @('.WT_REGEX_XREF.')@/', $famrec, $match);
if ($ct>0) {
$parents["HUSB"]=$match[1];
} else {
$parents["HUSB"]="";
}
$ct = preg_match('/1 WIFE @('.WT_REGEX_XREF.')@/', $famrec, $match);
if ($ct>0) {
$parents["WIFE"]=$match[1];
} else {
$parents["WIFE"]="";
}
return $parents;
}
/**
* find the children in a family
*
* find and return an array containing the children of the given family record
* @author John Finlay (yalnifj)
* @param string $famid the gedcom xref id for the family
* @param string $me an xref id of a child to ignore, useful when you want to get a person's
* siblings but do want to include them as well
* @return array
*/
function find_children($famid, $me='') {
$famrec = find_gedcom_record($famid, WT_GED_ID, true);
if (empty($famrec)) {
return false;
}
return find_children_in_record($famrec);
}
/**
* find the children in a family record
*
* find and return an array containing the children of the given family record
* @author John Finlay (yalnifj)
* @param string $famrec the gedcom record of the family to search in
* @param string $me an xref id of a child to ignore, useful when you want to get a person's
* siblings but do want to include them as well
* @return array
*/
function find_children_in_record($famrec, $me='') {
$children = array();
if (empty($famrec)) {
return $children;
}
$num = preg_match_all('/\n1 CHIL @('.WT_REGEX_XREF.')@/', $famrec, $match, PREG_SET_ORDER);
for ($i=0; $i<$num; $i++) {
$child = trim($match[$i][1]);
if ($child!=$me) {
$children[] = $child;
}
}
return $children;
}
/**
* find all child family ids
*
* searches an individual gedcom record and returns an array of the FAMC ids where this person is a
* child in the family, but only those families that are allowed to be seen by current user
* @param string $pid the gedcom xref id for the person to look in
* @return array array of family ids
*/
function find_family_ids($pid) {
$indirec=find_person_record($pid, WT_GED_ID);
return find_visible_families_in_record($indirec, "FAMC");
}
/**
* find all spouse family ids
*
* searches an individual gedcom record and returns an array of the FAMS ids where this person is a
* spouse in the family, but only those families that are allowed to be seen by current user
* @param string $pid the gedcom xref id for the person to look in
* @return array array of family ids
*/
function find_sfamily_ids($pid) {
$indirec=find_person_record($pid, WT_GED_ID);
return find_visible_families_in_record($indirec, "FAMS");
}
/**
* find all family ids in the given record
*
* searches an individual gedcom record and returns an array of the FAMS|C ids
* @param string $indirec the gedcom record for the person to look in
* @param string $tag The family tag to look for
* @return array array of family ids
*/
function find_families_in_record($indirec, $tag) {
preg_match_all("/\n1 {$tag} @(".WT_REGEX_XREF.')@/', $indirec, $match);
return $match[1];
}
/**
* find all family ids in the given record that should be visible to the current user
*
* searches an individual gedcom record and returns an array of the FAMS|C ids that are visible
* @param string $indirec the gedcom record for the person to look in
* @param string $tag The family tag to look for, FAMS or FAMC
* @return array array of family ids
*/
function find_visible_families_in_record($indirec, $tag) {
$allfams = find_families_in_record($indirec, $tag);
$visiblefams = array();
// select only those that are visible to current user
foreach ($allfams as $key=>$famid) {
if (displayDetailsById($famid, "FAM")) {
$visiblefams[] = $famid;
}
}
return $visiblefams;
}
// ************************************************* START OF MULTIMEDIA FUNCTIONS ********************************* //
/**
* find the highlighted media object for a gedcom entity
* 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"
* (d) Level 2 or higher object with the Highlight option missing or set to other than "Y" or "N"
* Criterion (d) will be present in the code but will be commented out for now.
*
* @param string $pid the individual, source, or family id
* @param string $indirec the gedcom record to look in
* @return array an object array with indexes "thumb" and "file" for thumbnail and filename
*/
function find_highlighted_object($pid, $ged_id, $indirec) {
global $MEDIA_DIRECTORY, $MEDIA_DIRECTORY_LEVELS, $WT_IMAGE_DIR, $WT_IMAGES, $MEDIA_EXTERNAL;
if (!showFact("OBJE", $pid)) {
return false;
}
$media = array();
$objectA = array();
$objectB = array();
$objectC = array();
$objectD = array();
//-- handle finding the media of remote objects
$ct = preg_match("/(.*):(.*)/", $pid, $match);
if ($ct>0) {
require_once WT_ROOT.'includes/classes/class_serviceclient.php';
$client = ServiceClient::getInstance($match[1]);
if (!is_null($client)) {
$mt = preg_match_all('/\n\d OBJE @('.WT_REGEX_XREF.')@/', $indirec, $matches, PREG_SET_ORDER);
for ($i=0; $i<$mt; $i++) {
$mediaObj = Media::getInstance($matches[$i][1]);
$mrec = $mediaObj->getGedcomRecord();
if (!empty($mrec)) {
$file = get_gedcom_value("FILE", 1, $mrec);
$row = array($matches[$i][1], $file, $mrec, $matches[$i][0]);
$media[] = $row;
}
}
}
}
//-- find all of the media items for a person
$media=
WT_DB::prepare("SELECT m_media, m_file, m_gedrec, mm_gedrec FROM `##media`, `##media_mapping` WHERE m_media=mm_media AND m_gedfile=mm_gedfile AND m_gedfile=? AND mm_gid=? ORDER BY mm_order")
->execute(array($ged_id, $pid))
->fetchAll(PDO::FETCH_NUM);
foreach ($media as $i=>$row) {
if (displayDetailsById($row[0], 'OBJE') && !FactViewRestricted($row[0], $row[2])) {
$level=0;
$ct = preg_match("/(\d+) OBJE/", $row[3], $match);
if ($ct>0) {
$level = $match[1];
}
if (strstr($row[3], "_PRIM ")) {
$thum = get_gedcom_value('_THUM', $level+1, $row[3]);
$prim = get_gedcom_value('_PRIM', $level+1, $row[3]);
} else {
$thum = get_gedcom_value('_THUM', 1, $row[2]);
$prim = get_gedcom_value('_PRIM', 1, $row[2]);
}
if ($prim=='N') continue; // Skip _PRIM N objects
$file = check_media_depth($row[1]);
$thumb = thumbnail_file($row[1], true, false, $pid);
if ($level == 1) {
if ($prim == 'Y') {
if (empty($objectA)) {
$objectA['file'] = $file;
$objectA['thumb'] = $thumb;
$objectA['_THUM'] = $thum; // This overrides GEDCOM's "Use main image as thumbnail" option
$objectA['level'] = $level;
$objectA['mid'] = $row[0];
}
} else {
if (empty($objectB)) {
$objectB['file'] = $file;
$objectB['thumb'] = $thumb;
$objectB['_THUM'] = $thum; // This overrides GEDCOM's "Use main image as thumbnail" option
$objectB['level'] = $level;
$objectB['mid'] = $row[0];
}
}
} else {
if ($prim == 'Y') {
if (empty($objectC)) {
$objectC['file'] = $file;
$objectC['thumb'] = $thumb;
$objectC['_THUM'] = $thum; // This overrides GEDCOM's "Use main image as thumbnail" option
$objectC['level'] = $level;
$objectC['mid'] = $row[0];
}
} else {
if (empty($objectD)) {
$objectD['file'] = $file;
$objectD['thumb'] = $thumb;
$objectD['_THUM'] = $thum; // This overrides GEDCOM's "Use main image as thumbnail" option
$objectD['level'] = $level;
$objectD['mid'] = $row[0];
}
}
}
}
}
if (!empty($objectA)) return $objectA;
if (!empty($objectB)) return $objectB;
if (!empty($objectC)) return $objectC;
// if (!empty($objectD)) return $objectD;
return array();
}
/**
* Determine whether the main image or a thumbnail should be sent to the browser
*/
function thumb_or_main($object) {
global $USE_THUMBS_MAIN;
if ($object['_THUM']=='Y' || !$USE_THUMBS_MAIN) $file = 'file';
else $file = 'thumb';
// Here we should check whether the selected file actually exists
return($object[$file]);
}
/**
* get the full file path
*
* get the file path from a multimedia gedcom record
* @param string $mediarec a OBJE subrecord
* @return the fullpath from the FILE record
*/
function extract_fullpath($mediarec) {
preg_match("/(\d) _*FILE (.*)/", $mediarec, $amatch);
if (empty($amatch[2])) {
return "";
}
$level = trim($amatch[1]);
$fullpath = trim($amatch[2]);
$filerec = get_sub_record($level, $amatch[0], $mediarec);
$fullpath .= get_cont($level+1, $filerec);
return $fullpath;
}
/**
* get the relative filename for a media item
*
* gets the relative file path from the full media path for a media item. checks the
* $MEDIA_DIRECTORY_LEVELS to make sure the directory structure is maintained.
* @param string $fullpath the full path from the media record
* @return string a relative path that can be appended to the $MEDIA_DIRECTORY to reference the item
*/
function extract_filename($fullpath) {
global $MEDIA_DIRECTORY_LEVELS, $MEDIA_DIRECTORY;
$filename="";
$regexp = "'[/\\\]'";
$srch = "/".addcslashes($MEDIA_DIRECTORY, '/.')."/";
$repl = "";
if (!isFileExternal($fullpath)) {
$nomedia = stripcslashes(preg_replace($srch, $repl, $fullpath));
} else {
$nomedia = $fullpath;
}
$ct = preg_match($regexp, $nomedia, $match);
if ($ct>0) {
$subelements = preg_split($regexp, $nomedia);
$subelements = array_reverse($subelements);
$max = $MEDIA_DIRECTORY_LEVELS;
if ($max>=count($subelements)) {
$max=count($subelements)-1;
}
for ($s=$max; $s>=0; $s--) {
if ($s!=$max) {
$filename = $filename."/".$subelements[$s];
} else {
$filename = $subelements[$s];
}
}
} else {
$filename = $nomedia;
}
return $filename;
}
// ************************************************* START OF SORTING FUNCTIONS ********************************* //
/**
* Function to sort GEDCOM fact tags based on their tanslations
*/
function factsort($a, $b) {
return utf8_strcasecmp(i18n::translate($a), i18n::translate($b));
}
/**
* Function to sort place names array
*/
function placesort($a, $b) {
return utf8_strcasecmp($a['place'], $b['place']);
}
////////////////////////////////////////////////////////////////////////////////
// Sort a list events for the today/upcoming blocks
////////////////////////////////////////////////////////////////////////////////
function event_sort($a, $b) {
if ($a['jd']==$b['jd']) {
if ($a['anniv']==$b['anniv']) {
return utf8_strcasecmp($a['fact'], $b['fact']);
}
else {
return utf8_strcasecmp($a['anniv'], $b['anniv']);
}
} else {
return $a['jd']-$b['jd'];
}
}
function event_sort_name($a, $b) {
if ($a['jd']==$b['jd']) {
return GedcomRecord::compare($a['record'], $b['record']);
} else {
return $a['jd']-$b['jd'];
}
}
/**
* sort an array of media items
*
*/
function mediasort($a, $b) {
$aKey = "";
if (!empty($a["TITL"])) {
$aKey = $a["TITL"];
} else {
if (!empty($a["titl"])) {
$aKey = $a["titl"];
} else {
if (!empty($a["NAME"])) {
$aKey = $a["NAME"];
} else {
if (!empty($a["name"])) {
$aKey = $a["name"];
} else {
if (!empty($a["FILE"])) {
$aKey = basename($a["FILE"]);
} else {
if (!empty($a["file"])) {
$aKey = basename($a["file"]);
}
}
}
}
}
}
$bKey = "";
if (!empty($b["TITL"])) {
$bKey = $b["TITL"];
} else {
if (!empty($b["titl"])) {
$bKey = $b["titl"];
} else {
if (!empty($b["NAME"])) {
$bKey = $b["NAME"];
} else {
if (!empty($b["name"])) {
$bKey = $b["name"];
} else {
if (!empty($b["FILE"])) {
$bKey = basename($b["FILE"]);
} else {
if (!empty($b["file"])) {
$bKey = basename($b["file"]);
}
}
}
}
}
}
return utf8_strcasecmp($aKey, $bKey, true); // Case-insensitive compare
}
/**
* sort an array according to the file name
*
*/
function filesort($a, $b) {
$aKey = "";
if (!empty($a["FILE"])) {
$aKey = basename($a["FILE"]);
} else if (!empty($a["file"])) {
$aKey = basename($a["file"]);
}
$bKey = "";
if (!empty($b["FILE"])) {
$bKey = basename($b["FILE"]);
} else if (!empty($b["file"])) {
$bKey = basename($b["file"]);
}
return utf8_strcasecmp($aKey, $bKey, true); // Case-insensitive compare
}
// Helper function to sort facts.
function compare_facts_date($arec, $brec) {
if (is_array($arec))
$arec = $arec[1];
if (is_array($brec))
$brec = $brec[1];
// If either fact is undated, the facts sort equally.
if (!preg_match("/2 _?DATE (.*)/", $arec, $amatch) || !preg_match("/2 _?DATE (.*)/", $brec, $bmatch)) {
if (preg_match('/2 _SORT (\d+)/', $arec, $match1) && preg_match('/2 _SORT (\d+)/', $brec, $match2)) {
return $match1[1]-$match2[1];
}
return 0;
}
$adate = new GedcomDate($amatch[1]);
$bdate = new GedcomDate($bmatch[1]);
// If either date can't be parsed, don't sort.
if (!$adate->isOK() || !$bdate->isOK()) {
if (preg_match('/2 _SORT (\d+)/', $arec, $match1) && preg_match('/2 _SORT (\d+)/', $brec, $match2)) {
return $match1[1]-$match2[1];
}
return 0;
}
// Remember that dates can be ranges and overlapping ranges sort equally.
$amin=$adate->MinJD();
$bmin=$bdate->MinJD();
$amax=$adate->MaxJD();
$bmax=$bdate->MaxJD();
// BEF/AFT XXX sort as the day before/after XXX
if ($adate->qual1=='BEF') {
$amin=$amin-1;
$amax=$amin;
} elseif ($adate->qual1=='AFT') {
$amax=$amax+1;
$amin=$amax;
}
if ($bdate->qual1=='BEF') {
$bmin=$bmin-1;
$bmax=$bmin;
} elseif ($bdate->qual1=='AFT') {
$bmax=$bmax+1;
$bmin=$bmax;
}
if ($amax<$bmin) {
return -1;
} else {
if ($amin>$bmax) {
return 1;
} else {
//-- ranged date... take the type of fact sorting into account
$factWeight = 0;
if (preg_match('/2 _SORT (\d+)/', $arec, $match1) && preg_match('/2 _SORT (\d+)/', $brec, $match2)) {
$factWeight = $match1[1]-$match2[1];
}
//-- fact is prefered to come before, so compare using the minimum ranges
if ($factWeight < 0 && $amin!=$bmin) {
return ($amin-$bmin);
} else {
if ($factWeight > 0 && $bmax!=$amax) {
//-- fact is prefered to come after, so compare using the max of the ranges
return ($bmax-$amax);
} else {
//-- facts are the same or the ranges don't give enough info, so use the average of the range
$aavg = ($amin+$amax)/2;
$bavg = ($bmin+$bmax)/2;
if ($aavg<$bavg) {
return -1;
} else {
if ($aavg>$bavg) {
return 1;
} else {
return $factWeight;
}
}
}
}
return 0;
}
}
}
/**
* A multi-key sort
* 1. First divide the facts into two arrays one set with dates and one set without dates
* 2. Sort each of the two new arrays, the date using the compare date function, the non-dated
* using the compare type function
* 3. Then merge the arrays back into the original array using the compare type function
*
* @param unknown_type $arr
*/
function sort_facts(&$arr) {
$dated = array();
$nondated = array();
//-- split the array into dated and non-dated arrays
$order = 0;
foreach($arr as $event) {
$event->sortOrder = $order;
$order++;
if ($event->getValue("DATE")==NULL || !$event->getDate()->isOk()) $nondated[] = $event;
else $dated[] = $event;
}
//-- sort each type of array
usort($dated, array("Event", "CompareDate"));
usort($nondated, array("Event", "CompareType"));
//-- merge the arrays back together comparing by Facts
$dc = count($dated);
$nc = count($nondated);
$i = 0;
$j = 0;
$k = 0;
// while there is anything in the dated array continue merging
while($i<$dc) {
// compare each fact by type to merge them in order
if ($j<$nc && Event::CompareType($dated[$i], $nondated[$j])>0) {
$arr[$k] = $nondated[$j];
$j++;
}
else {
$arr[$k] = $dated[$i];
$i++;
}
$k++;
}
// get anything that might be left in the nondated array
while($j<$nc) {
$arr[$k] = $nondated[$j];
$j++;
$k++;
}
}
function gedcomsort($a, $b) {
return utf8_strcasecmp($a["title"], $b["title"]);
}
// ************************************************* START OF MISCELLANIOUS FUNCTIONS ********************************* //
/**
* Get relationship between two individuals in the gedcom
*
* function to calculate the relationship between two people it uses hueristics based on the
* individuals birthdate to try and calculate the shortest path between the two individuals
* it uses a node cache to help speed up calculations when using relationship privacy
* this cache is indexed using the string "$pid1-$pid2"
* @param string $pid1 the ID of the first person to compute the relationship from
* @param string $pid2 the ID of the second person to compute the relatiohip to
* @param bool $followspouse whether to add spouses to the path
* @param int $maxlenght the maximim length of path
* @param bool $ignore_cache enable or disable the relationship cache
* @param int $path_to_find which path in the relationship to find, 0 is the shortest path, 1 is the next shortest path, etc
*/
function get_relationship($pid1, $pid2, $followspouse=true, $maxlength=0, $ignore_cache=false, $path_to_find=0) {
global $start_time, $NODE_CACHE, $NODE_CACHE_LENGTH, $USE_RELATIONSHIP_PRIVACY;
$time_limit=get_site_setting('MAX_EXECUTION_TIME');
$indirec = find_gedcom_record($pid2, WT_GED_ID, WT_USER_CAN_EDIT);
//-- check the cache
if ($USE_RELATIONSHIP_PRIVACY && !$ignore_cache) {
if (isset($NODE_CACHE["$pid1-$pid2"])) {
if ($NODE_CACHE["$pid1-$pid2"]=="NOT FOUND") return false;
if (($maxlength==0)||(count($NODE_CACHE["$pid1-$pid2"]["path"])-1<=$maxlength))
return $NODE_CACHE["$pid1-$pid2"];
else
return false;
}
//-- check the cache for person 2's children
$famids = array();
$ct = preg_match_all("/1 FAMS @(.*)@/", $indirec, $match, PREG_SET_ORDER);
for ($i=0; $i<$ct; $i++) {
$famids[$i]=$match[$i][1];
}
foreach ($famids as $indexval => $fam) {
$famrec = find_gedcom_record($fam, WT_GED_ID, WT_USER_CAN_EDIT);
$ct = preg_match_all("/1 CHIL @(.*)@/", $famrec, $match, PREG_SET_ORDER);
for ($i=0; $i<$ct; $i++) {
$child = $match[$i][1];
if (!empty($child)) {
if (isset($NODE_CACHE["$pid1-$child"])) {
if (($maxlength==0)||(count($NODE_CACHE["$pid1-$child"]["path"])+1<=$maxlength)) {
$node1 = $NODE_CACHE["$pid1-$child"];
if ($node1!="NOT FOUND") {
$node1["path"][] = $pid2;
$node1["pid"] = $pid2;
if (strpos($indirec, "1 SEX F")!==false)
$node1["relations"][] = "mother";
else
$node1["relations"][] = "father";
}
$NODE_CACHE["$pid1-$pid2"] = $node1;
if ($node1=="NOT FOUND")
return false;
return $node1;
} else
return false;
}
}
}
}
if ((!empty($NODE_CACHE_LENGTH))&&($maxlength>0)) {
if ($NODE_CACHE_LENGTH>=$maxlength)
return false;
}
}
//-- end cache checking
//-- get the birth year of p2 for calculating heuristics
$birthrec = get_sub_record(1, "1 BIRT", $indirec);
$byear2 = -1;
if ($birthrec!==false) {
$dct = preg_match("/2 DATE .*(\d\d\d\d)/", $birthrec, $match);
if ($dct>0)
$byear2 = $match[1];
}
if ($byear2==-1) {
$numfams = preg_match_all("/1 FAMS @(.*)@/", $indirec, $fmatch, PREG_SET_ORDER);
for ($j=0; $j<$numfams; $j++) {
// Get the family record
$famrec = find_gedcom_record($fmatch[$j][1], WT_GED_ID, WT_USER_CAN_EDIT);
// Get the set of children
$ct = preg_match_all("/1 CHIL @(.*)@/", $famrec, $cmatch, PREG_SET_ORDER);
for ($i=0; $i<$ct; $i++) {
// Get each child's record
$childrec = find_gedcom_record($cmatch[$i][1], WT_GED_ID, WT_USER_CAN_EDIT);
$birthrec = get_sub_record(1, "1 BIRT", $childrec);
if ($birthrec!==false) {
$dct = preg_match("/2 DATE .*(\d\d\d\d)/", $birthrec, $bmatch);
if ($dct>0)
$byear2 = $bmatch[1]-25;
if ($byear2>2100) $byear2-=3760; // Crude conversion from jewish to gregorian
}
}
}
}
//-- end of approximating birth year
//-- current path nodes
$p1nodes = array();
//-- ids visited
$visited = array();
//-- set up first node for person1
$node1 = array();
$node1["path"] = array();
$node1["path"][] = $pid1;
$node1["length"] = 0;
$node1["pid"] = $pid1;
$node1["relations"] = array();
$node1["relations"][] = "self";
$p1nodes[] = $node1;
$visited[$pid1] = true;
$found = false;
$count=0;
while (!$found) {
//-- the following 2 lines ensure that the user can abort a long relationship calculation
//-- refer to http://www.php.net/manual/en/features.connection-handling.php for more
//-- information about why these lines are included
if (headers_sent()) {
print " ";
if ($count%100 == 0)
flush();
}
$count++;
$end_time = microtime(true);
$exectime = $end_time - $start_time;
if (($time_limit>1)&&($exectime > $time_limit-1)) {
echo "", i18n::translate('The script timed out before a relationship could be found.'), "\n";
return false;
}
if (count($p1nodes)==0) {
if ($maxlength!=0) {
if (!isset($NODE_CACHE_LENGTH)) {
$NODE_CACHE_LENGTH = $maxlength;
} elseif ($NODE_CACHE_LENGTH<$maxlength) {
$NODE_CACHE_LENGTH = $maxlength;
}
}
if (headers_sent()) {
//print "\n\n";
}
$NODE_CACHE["$pid1-$pid2"] = "NOT FOUND";
return false;
}
//-- search the node list for the shortest path length
$shortest = -1;
foreach ($p1nodes as $index=>$node) {
if ($shortest == -1) {
$shortest = $index;
} else {
$node1 = $p1nodes[$shortest];
if ($node1["length"] > $node["length"]) {
$shortest = $index;
}
}
}
if ($shortest==-1)
return false;
$node = $p1nodes[$shortest];
if (($maxlength==0)||(count($node["path"])<=$maxlength)) {
if ($node["pid"]==$pid2) {
} else {
//-- hueristic values
$fatherh = 1;
$motherh = 1;
$siblingh = 2;
$spouseh = 2;
$childh = 3;
//-- generate heuristic values based of the birthdates of the current node and p2
$indirec = find_gedcom_record($node["pid"], WT_GED_ID, WT_USER_CAN_EDIT);
$byear1 = -1;
$birthrec = get_sub_record(1, "1 BIRT", $indirec);
if ($birthrec!==false) {
$dct = preg_match("/2 DATE .*(\d\d\d\d)/", $birthrec, $match);
if ($dct>0)
$byear1 = $match[1];
if ($byear1>2100) $byear1-=3760; // Crude conversion from jewish to gregorian
}
if (($byear1!=-1)&&($byear2!=-1)) {
$yeardiff = $byear1-$byear2;
if ($yeardiff < -140) {
$fatherh = 20;
$motherh = 20;
$siblingh = 15;
$spouseh = 15;
$childh = 1;
} else
if ($yeardiff < -100) {
$fatherh = 15;
$motherh = 15;
$siblingh = 10;
$spouseh = 10;
$childh = 1;
} else
if ($yeardiff < -60) {
$fatherh = 10;
$motherh = 10;
$siblingh = 5;
$spouseh = 5;
$childh = 1;
} else
if ($yeardiff < -20) {
$fatherh = 5;
$motherh = 5;
$siblingh = 3;
$spouseh = 3;
$childh = 1;
} else
if ($yeardiff<20) {
$fatherh = 3;
$motherh = 3;
$siblingh = 1;
$spouseh = 1;
$childh = 5;
} else
if ($yeardiff<60) {
$fatherh = 1;
$motherh = 1;
$siblingh = 5;
$spouseh = 2;
$childh = 10;
} else
if ($yeardiff<100) {
$fatherh = 1;
$motherh = 1;
$siblingh = 10;
$spouseh = 3;
$childh = 15;
} else {
$fatherh = 1;
$motherh = 1;
$siblingh = 15;
$spouseh = 4;
$childh = 20;
}
}
//-- check all parents and siblings of this node
$famids = array();
$ct = preg_match_all("/1 FAMC @(.*)@/", $indirec, $match, PREG_SET_ORDER);
for ($i=0; $i<$ct; $i++) {
if (!isset($visited[$match[$i][1]]))
$famids[$i]=$match[$i][1];
}
foreach ($famids as $indexval => $fam) {
$visited[$fam] = true;
$famrec = find_gedcom_record($fam, WT_GED_ID, WT_USER_CAN_EDIT);
$parents = find_parents_in_record($famrec);
if ((!empty($parents["HUSB"]))&&(!isset($visited[$parents["HUSB"]]))) {
$node1 = $node;
$node1["length"]+=$fatherh;
$node1["path"][] = $parents["HUSB"];
$node1["pid"] = $parents["HUSB"];
$node1["relations"][] = "parent";
$p1nodes[] = $node1;
if ($node1["pid"]==$pid2) {
if ($path_to_find>0)
$path_to_find--;
else {
$found=true;
$resnode = $node1;
}
} else
$visited[$parents["HUSB"]] = true;
if ($USE_RELATIONSHIP_PRIVACY) {
$NODE_CACHE["$pid1-".$node1["pid"]] = $node1;
}
}
if ((!empty($parents["WIFE"]))&&(!isset($visited[$parents["WIFE"]]))) {
$node1 = $node;
$node1["length"]+=$motherh;
$node1["path"][] = $parents["WIFE"];
$node1["pid"] = $parents["WIFE"];
$node1["relations"][] = "parent";
$p1nodes[] = $node1;
if ($node1["pid"]==$pid2) {
if ($path_to_find>0)
$path_to_find--;
else {
$found=true;
$resnode = $node1;
}
} else
$visited[$parents["WIFE"]] = true;
if ($USE_RELATIONSHIP_PRIVACY) {
$NODE_CACHE["$pid1-".$node1["pid"]] = $node1;
}
}
$ct = preg_match_all("/1 CHIL @(.*)@/", $famrec, $match, PREG_SET_ORDER);
for ($i=0; $i<$ct; $i++) {
$child = $match[$i][1];
if ((!empty($child))&&(!isset($visited[$child]))) {
$node1 = $node;
$node1["length"]+=$siblingh;
$node1["path"][] = $child;
$node1["pid"] = $child;
$node1["relations"][] = "sibling";
$p1nodes[] = $node1;
if ($node1["pid"]==$pid2) {
if ($path_to_find>0)
$path_to_find--;
else {
$found=true;
$resnode = $node1;
}
} else
$visited[$child] = true;
if ($USE_RELATIONSHIP_PRIVACY) {
$NODE_CACHE["$pid1-".$node1["pid"]] = $node1;
}
}
}
}
//-- check all spouses and children of this node
$famids = array();
$ct = preg_match_all("/1 FAMS @(.*)@/", $indirec, $match, PREG_SET_ORDER);
for ($i=0; $i<$ct; $i++) {
$famids[$i]=$match[$i][1];
}
foreach ($famids as $indexval => $fam) {
$visited[$fam] = true;
$famrec = find_gedcom_record($fam, WT_GED_ID, WT_USER_CAN_EDIT);
if ($followspouse) {
$parents = find_parents_in_record($famrec);
if ((!empty($parents["HUSB"]))&&((!in_arrayr($parents["HUSB"], $node1))||(!isset($visited[$parents["HUSB"]])))) {
$node1 = $node;
$node1["length"]+=$spouseh;
$node1["path"][] = $parents["HUSB"];
$node1["pid"] = $parents["HUSB"];
$node1["relations"][] = "spouse";
$p1nodes[] = $node1;
if ($node1["pid"]==$pid2) {
if ($path_to_find>0)
$path_to_find--;
else {
$found=true;
$resnode = $node1;
}
} else
$visited[$parents["HUSB"]] = true;
if ($USE_RELATIONSHIP_PRIVACY) {
$NODE_CACHE["$pid1-".$node1["pid"]] = $node1;
}
}
if ((!empty($parents["WIFE"]))&&((!in_arrayr($parents["WIFE"], $node1))||(!isset($visited[$parents["WIFE"]])))) {
$node1 = $node;
$node1["length"]+=$spouseh;
$node1["path"][] = $parents["WIFE"];
$node1["pid"] = $parents["WIFE"];
$node1["relations"][] = "spouse";
$p1nodes[] = $node1;
if ($node1["pid"]==$pid2) {
if ($path_to_find>0)
$path_to_find--;
else {
$found=true;
$resnode = $node1;
}
} else
$visited[$parents["WIFE"]] = true;
if ($USE_RELATIONSHIP_PRIVACY) {
$NODE_CACHE["$pid1-".$node1["pid"]] = $node1;
}
}
}
$ct = preg_match_all("/1 CHIL @(.*)@/", $famrec, $match, PREG_SET_ORDER);
for ($i=0; $i<$ct; $i++) {
$child = $match[$i][1];
if ((!empty($child))&&(!isset($visited[$child]))) {
$node1 = $node;
$node1["length"]+=$childh;
$node1["path"][] = $child;
$node1["pid"] = $child;
$node1["relations"][] = "child";
$p1nodes[] = $node1;
if ($node1["pid"]==$pid2) {
if ($path_to_find>0)
$path_to_find--;
else {
$found=true;
$resnode = $node1;
}
} else {
$visited[$child] = true;
}
if ($USE_RELATIONSHIP_PRIVACY) {
$NODE_CACHE["$pid1-".$node1["pid"]] = $node1;
}
}
}
}
}
}
unset($p1nodes[$shortest]);
} //-- end while loop
if (headers_sent()) {
//echo "\n\n";
}
// Convert "generic" relationships into sex-specific ones.
foreach ($resnode['path'] as $n=>$pid) {
switch ($resnode['relations'][$n]) {
case 'parent':
switch (Person::getInstance($pid)->getSex()) {
case 'M': $resnode['relations'][$n]='father'; break;
case 'F': $resnode['relations'][$n]='mother'; break;
}
break;
case 'child':
switch (Person::getInstance($pid)->getSex()) {
case 'M': $resnode['relations'][$n]='son'; break;
case 'F': $resnode['relations'][$n]='daughter'; break;
}
break;
case 'spouse':
switch (Person::getInstance($pid)->getSex()) {
case 'M': $resnode['relations'][$n]='husband'; break;
case 'F': $resnode['relations'][$n]='wife'; break;
}
break;
case 'sibling':
switch (Person::getInstance($pid)->getSex()) {
case 'M': $resnode['relations'][$n]='brother'; break;
case 'F': $resnode['relations'][$n]='sister'; break;
}
break;
}
}
return $resnode;
}
// Convert the result of get_relationship() into a relationship name.
function get_relationship_name($nodes) {
if (!is_array($nodes)) {
return '';
}
$pid1=$nodes['path'][0];
$pid2=$nodes['path'][count($nodes['path'])-1];
$path=array_slice($nodes['relations'], 1);
// Look for paths with *specific* names first.
// Note that every combination must be listed separately, as the same english
// name can be used for many different relationships. e.g.
// brother's wife & husband's sister = sister-in-law.
//
// $path is an array of the 12 possible gedcom family relationships:
// mother/father/parent
// brother/sister/sibling
// husband/wife/spouse
// son/daughter/child
//
// This is always the shortest path, so "father, daughter" is "half-sister", not "sister".
//
// This is very repetitive in english, but necessary in order to handle the
// complexities of other languages.
//
// TODO: handle unmarried partners, so need male-partner, female-partner, unknown-partner
// Make each relationship parts the same length, for simpler matching.
$combined_path='';
foreach ($path as $rel) {
$combined_path.=substr($rel, 0, 3);
}
return get_relationship_name_from_path($combined_path, $pid1, $pid2);
}
function get_relationship_name_from_path($path, $pid1, $pid2) {
if (!preg_match('/^(mot|fat|par|hus|wif|spo|son|dau|chi|bro|sis|sib)*$/', $path)) {
// TODO: Update all the "3 RELA " values in class_person
return ''.$path.'';
}
switch ($path) {
case '': return i18n::translate('self');
// Level One relationships
case 'mot': return i18n::translate('mother');
case 'fat': return i18n::translate('father');
case 'par': return i18n::translate('parent');
case 'hus': return i18n::translate('husband');
case 'wif': return i18n::translate('wife');
case 'spo': return i18n::translate('spouse');
case 'son': return i18n::translate('son');
case 'dau': return i18n::translate('daughter');
case 'chi': return i18n::translate('child');
case 'bro':
$dob1=Person::GetInstance($pid1)->getBirthDate();
$dob2=Person::GetInstance($pid2)->getBirthDate();
if ($dob1->isOK() && $dob2->isOK()) {
if (abs($dob1->JD()-$dob2->JD())<2) {
return i18n::translate('twin brother');
} else if ($dob1->JD()<$dob2->JD()) {
return i18n::translate('younger brother');
} else {
return i18n::translate('elder brother');
}
}
return i18n::translate('brother');
case 'sis':
$dob1=Person::GetInstance($pid1)->getBirthDate();
$dob2=Person::GetInstance($pid2)->getBirthDate();
if ($dob1->isOK() && $dob2->isOK()) {
if (abs($dob1->JD()-$dob2->JD())<2) {
return i18n::translate('twin sister');
} else if ($dob1->JD()<$dob2->JD()) {
return i18n::translate('younger sister');
} else {
return i18n::translate('elder sister');
}
}
return i18n::translate('sister');
case 'sib':
$dob1=Person::GetInstance($pid1)->getBirthDate();
$dob2=Person::GetInstance($pid2)->getBirthDate();
if ($dob1->isOK() && $dob2->isOK()) {
if (abs($dob1->JD()-$dob2->JD())<2) {
return i18n::translate('twin sibling');
} else if ($dob1->JD()<$dob2->JD()) {
return i18n::translate('younger sibling');
} else {
return i18n::translate('elder sibling');
}
}
return i18n::translate('sibling');
// Level Two relationships
case 'brochi': return i18n::translate_c('brother\'s child', 'nephew/niece');
case 'brodau': return i18n::translate_c('brother\'s daughter', 'niece');
case 'broson': return i18n::translate_c('brother\'s son', 'nephew');
case 'browif': return i18n::translate_c('brother\'s wife', 'sister-in-law');
case 'chichi': return i18n::translate_c('child\'s child', 'grandchild');
case 'chidau': return i18n::translate_c('child\'s daughter', 'granddaughter');
case 'chihus': return i18n::translate_c('child\'s husband', 'son-in-law');
case 'chison': return i18n::translate_c('child\'s son', 'grandson');
case 'chispo': return i18n::translate_c('child\'s spouse', 'son/daughter-in-law');
case 'chiwif': return i18n::translate_c('child\'s wife', 'daughter-in-law');
case 'dauchi': return i18n::translate_c('daughter\'s child', 'grandchild');
case 'daudau': return i18n::translate_c('daughter\'s daughter', 'granddaughter');
case 'dauhus': return i18n::translate_c('daughter\'s husband', 'son-in-law');
case 'dauson': return i18n::translate_c('daughter\'s son', 'grandson');
case 'fatbro': return i18n::translate_c('father\'s brother', 'uncle');
case 'fatchi': return i18n::translate_c('father\'s child', 'half-sibling');
case 'fatdau': return i18n::translate_c('father\'s daughter', 'half-sister');
case 'fatfat': return i18n::translate_c('father\'s father', 'grandfather');
case 'fatmot': return i18n::translate_c('father\'s mother', 'grandmother');
case 'fatpar': return i18n::translate_c('father\'s parent', 'grandparent');
case 'fatsib': return i18n::translate_c('father\'s sibling', 'aunt/uncle');
case 'fatsis': return i18n::translate_c('father\'s sister', 'aunt');
case 'fatson': return i18n::translate_c('father\'s son', 'half-brother');
case 'fatwif': return i18n::translate_c('father\'s wife', 'step-mother');
case 'husbro': return i18n::translate_c('husband\'s brother', 'brother-in-law');
case 'huschi': return i18n::translate_c('husband\'s child', 'step-child');
case 'husdau': return i18n::translate_c('husband\'s daughter', 'step-daughter');
case 'husfat': return i18n::translate_c('husband\'s father', 'father-in-law');
case 'husmot': return i18n::translate_c('husband\'s mother', 'mother-in-law');
case 'hussib': return i18n::translate_c('husband\'s sibling', 'brother/sister-in-law');
case 'hussis': return i18n::translate_c('husband\'s sister', 'sister-in-law');
case 'husson': return i18n::translate_c('husband\'s son', 'step-son');
case 'motbro': return i18n::translate_c('mother\'s brother', 'uncle');
case 'motchi': return i18n::translate_c('mother\'s child', 'half-sibling');
case 'motdau': return i18n::translate_c('mother\'s daughter', 'half-sister');
case 'motfat': return i18n::translate_c('mother\'s father', 'grandfather');
case 'mothus': return i18n::translate_c('mother\'s husband', 'step-father');
case 'motmot': return i18n::translate_c('mother\'s mother', 'grandmother');
case 'motpar': return i18n::translate_c('mother\'s parent', 'grandparent');
case 'motsib': return i18n::translate_c('mother\'s sibling', 'aunt/uncle');
case 'motsis': return i18n::translate_c('mother\'s sister', 'aunt');
case 'motson': return i18n::translate_c('mother\'s son', 'half-brother');
case 'parbro': return i18n::translate_c('parent\'s brother', 'uncle');
case 'parchi': return i18n::translate_c('parent\'s child', 'half-sibling');
case 'pardau': return i18n::translate_c('parent\'s daughter', 'half-sister');
case 'parfat': return i18n::translate_c('parent\'s father', 'grandfather');
case 'parmot': return i18n::translate_c('parent\'s mother', 'grandmother');
case 'parpar': return i18n::translate_c('parent\'s parent', 'grandparent');
case 'parsib': return i18n::translate_c('parent\'s sibling', 'aunt/uncle');
case 'parsis': return i18n::translate_c('parent\'s sister', 'aunt');
case 'parson': return i18n::translate_c('parent\'s son', 'half-brother');
case 'parspo': return i18n::translate_c('parent\'s spouse', 'step-parent');
case 'sibchi': return i18n::translate_c('sibling\'s child', 'nephew/niece');
case 'sibdau': return i18n::translate_c('sibling\'s daughter', 'niece');
case 'sibson': return i18n::translate_c('sibling\'s son', 'nephew');
case 'sibspo': return i18n::translate_c('sibling\'s wife', 'brother/sister-in-law');
case 'sischi': return i18n::translate_c('sister\'s child', 'nephew/niece');
case 'sisdau': return i18n::translate_c('sister\'s daughter', 'niece');
case 'sishus': return i18n::translate_c('sister\'s husband', 'brother-in-law');
case 'sisson': return i18n::translate_c('sister\'s son', 'nephew');
case 'sonchi': return i18n::translate_c('son\'s child', 'grandchild');
case 'sondau': return i18n::translate_c('son\'s daughter', 'granddaughter');
case 'sonson': return i18n::translate_c('son\'s son', 'grandson');
case 'sonwif': return i18n::translate_c('son\'s wife', 'daughter-in-law');
case 'spobro': return i18n::translate_c('spouses\'s brother', 'brother-in-law');
case 'spochi': return i18n::translate_c('spouses\'s child', 'step-child');
case 'spodau': return i18n::translate_c('spouses\'s daughter', 'step-daughter');
case 'spofat': return i18n::translate_c('spouses\'s father', 'father-in-law');
case 'spomot': return i18n::translate_c('spouses\'s mother', 'mother-in-law');
case 'sposis': return i18n::translate_c('spouses\'s sister', 'sister-in-law');
case 'sposon': return i18n::translate_c('spouses\'s son', 'step-son');
case 'spopar': return i18n::translate_c('spouses\'s parent', 'mother/father-in-law');
case 'sposib': return i18n::translate_c('spouses\'s sibling', 'brother/sister-in-law');
case 'wifbro': return i18n::translate_c('wife\'s brother', 'brother-in-law');
case 'wifchi': return i18n::translate_c('wife\'s child', 'step-child');
case 'wifdau': return i18n::translate_c('wife\'s daughter', 'step-daughter');
case 'wiffat': return i18n::translate_c('wife\'s father', 'father-in-law');
case 'wifmot': return i18n::translate_c('wife\'s mother', 'mother-in-law');
case 'wifsib': return i18n::translate_c('wife\'s sibling', 'brother/sister-in-law');
case 'wifsis': return i18n::translate_c('wife\'s sister', 'sister-in-law');
case 'wifson': return i18n::translate_c('wife\'s son', 'step-son');
// Level Three relationships
case 'motmotmot': return i18n::translate_c('mother\'s mother\'s mother', 'great-grandmother');
case 'motmotfat': return i18n::translate_c('mother\'s mother\'s father', 'great-grandfather');
case 'motmotpar': return i18n::translate_c('mother\'s mother\'s parent', 'great-grandparent');
case 'motfatmot': return i18n::translate_c('mother\'s father\'s mother', 'great-grandmother');
case 'motfatfat': return i18n::translate_c('mother\'s father\'s father', 'great-grandfather');
case 'motfatpar': return i18n::translate_c('mother\'s father\'s parent', 'great-grandparent');
case 'motparmot': return i18n::translate_c('mother\'s parent\'s mother', 'great-grandmother');
case 'motparfat': return i18n::translate_c('mother\'s parent\'s father', 'great-grandfather');
case 'motparpar': return i18n::translate_c('mother\'s parent\'s parent', 'great-grandparent');
case 'fatmotmot': return i18n::translate_c('father\'s mother\'s mother', 'great-grandmother');
case 'fatmotfat': return i18n::translate_c('father\'s mother\'s father', 'great-grandfather');
case 'fatmotpar': return i18n::translate_c('father\'s mother\'s parent', 'great-grandparent');
case 'fatfatmot': return i18n::translate_c('father\'s father\'s mother', 'great-grandmother');
case 'fatfatfat': return i18n::translate_c('father\'s father\'s father', 'great-grandfather');
case 'fatfatpar': return i18n::translate_c('father\'s father\'s parent', 'great-grandparent');
case 'fatparmot': return i18n::translate_c('father\'s parent\'s mother', 'great-grandmother');
case 'fatparfat': return i18n::translate_c('father\'s parent\'s father', 'great-grandfather');
case 'fatparpar': return i18n::translate_c('father\'s parent\'s parent', 'great-grandparent');
case 'parmotmot': return i18n::translate_c('parent\'s mother\'s mother', 'great-grandmother');
case 'parmotfat': return i18n::translate_c('parent\'s mother\'s father', 'great-grandfather');
case 'parmotpar': return i18n::translate_c('parent\'s mother\'s parent', 'great-grandparent');
case 'parfatmot': return i18n::translate_c('parent\'s father\'s mother', 'great-grandmother');
case 'parfatfat': return i18n::translate_c('parent\'s father\'s father', 'great-grandfather');
case 'parfatpar': return i18n::translate_c('parent\'s father\'s parent', 'great-grandparent');
case 'parparmot': return i18n::translate_c('parent\'s parent\'s mother', 'great-grandmother');
case 'parparfat': return i18n::translate_c('parent\'s parent\'s father', 'great-grandfather');
case 'parparpar': return i18n::translate_c('parent\'s parent\'s parent', 'great-grandparent');
case 'motmotsis': return i18n::translate_c('mother\'s mother\'s sister', 'great-aunt');
case 'motmotbro': return i18n::translate_c('mother\'s mother\'s brother', 'great-uncle');
case 'motmotsib': return i18n::translate_c('mother\'s mother\'s sibling', 'great-aunt/uncle');
case 'motfatsis': return i18n::translate_c('mother\'s father\'s sister', 'great-aunt');
case 'motfatbro': return i18n::translate_c('mother\'s father\'s brother', 'great-uncle');
case 'motfatsib': return i18n::translate_c('mother\'s father\'s sibling', 'great-aunt/uncle');
case 'motparsis': return i18n::translate_c('mother\'s parent\'s sister', 'great-aunt');
case 'motparbro': return i18n::translate_c('mother\'s parent\'s brother', 'great-uncle');
case 'motparsib': return i18n::translate_c('mother\'s parent\'s sibling', 'great-aunt/uncle');
case 'fatmotsis': return i18n::translate_c('father\'s mother\'s sister', 'great-aunt');
case 'fatmotbro': return i18n::translate_c('father\'s mother\'s brother', 'great-uncle');
case 'fatmotsib': return i18n::translate_c('father\'s mother\'s sibling', 'great-aunt/uncle');
case 'fatfatsis': return i18n::translate_c('father\'s father\'s sister', 'great-aunt');
case 'fatfatbro': return i18n::translate_c('father\'s father\'s brother', 'great-uncle');
case 'fatfatsib': return i18n::translate_c('father\'s father\'s sibling', 'great-aunt/uncle');
case 'fatparsis': return i18n::translate_c('father\'s parent\'s sister', 'great-aunt');
case 'fatparbro': return i18n::translate_c('father\'s parent\'s brother', 'great-uncle');
case 'fatparsib': return i18n::translate_c('father\'s parent\'s sibling', 'great-aunt/uncle');
case 'parmotsis': return i18n::translate_c('parent\'s mother\'s sister', 'great-aunt');
case 'parmotbro': return i18n::translate_c('parent\'s mother\'s brother', 'great-uncle');
case 'parmotsib': return i18n::translate_c('parent\'s mother\'s sibling', 'great-aunt/uncle');
case 'parfatsis': return i18n::translate_c('parent\'s father\'s sister', 'great-aunt');
case 'parfatbro': return i18n::translate_c('parent\'s father\'s brother', 'great-uncle');
case 'parfatsib': return i18n::translate_c('parent\'s father\'s sibling', 'great-aunt/uncle');
case 'parparsis': return i18n::translate_c('parent\'s parent\'s sister', 'great-aunt');
case 'parparbro': return i18n::translate_c('parent\'s parent\'s brother', 'great-uncle');
case 'parparsib': return i18n::translate_c('parent\'s parent\'s sibling', 'great-aunt/uncle');
case 'brosonson': return i18n::translate_c('brother\'s son\'s son', 'great-nephew');
case 'brosondau': return i18n::translate_c('brother\'s son\'s daughter', 'great-niece');
case 'brosonchi': return i18n::translate_c('brother\'s son\'s child', 'great-nephew/niece');
case 'brodauson': return i18n::translate_c('brother\'s daughter\'s son', 'great-nephew');
case 'brodaudau': return i18n::translate_c('brother\'s daughter\'s daughter', 'great-niece');
case 'brodauchi': return i18n::translate_c('brother\'s daughter\'s child', 'great-nephew/niece');
case 'brochison': return i18n::translate_c('brother\'s child\'s son', 'great-nephew');
case 'brochidau': return i18n::translate_c('brother\'s child\'s daughter', 'great-niece');
case 'brochichi': return i18n::translate_c('brother\'s child\'s child', 'great-nephew/niece');
case 'sissonson': return i18n::translate_c('sister\'s son\'s son', 'great-nephew');
case 'sissondau': return i18n::translate_c('sister\'s son\'s daughter', 'great-niece');
case 'sissonchi': return i18n::translate_c('sister\'s son\'s child', 'great-nephew/niece');
case 'sisdauson': return i18n::translate_c('sister\'s daughter\'s son', 'great-nephew');
case 'sisdaudau': return i18n::translate_c('sister\'s daughter\'s daughter', 'great-niece');
case 'sisdauchi': return i18n::translate_c('sister\'s daughter\'s child', 'great-nephew/niece');
case 'sischison': return i18n::translate_c('sister\'s child\'s son', 'great-nephew');
case 'sischidau': return i18n::translate_c('sister\'s child\'s daughter', 'great-niece');
case 'sischichi': return i18n::translate_c('sister\'s child\'s child', 'great-nephew/niece');
case 'sibsonson': return i18n::translate_c('sibling\'s son\'s son', 'great-nephew');
case 'sibsondau': return i18n::translate_c('sibling\'s son\'s daughter', 'great-niece');
case 'sibsonchi': return i18n::translate_c('sibling\'s son\'s child', 'great-nephew/niece');
case 'sibdauson': return i18n::translate_c('sibling\'s daughte\'s sonr', 'great-nephew');
case 'sibdaudau': return i18n::translate_c('sibling\'s daughter\'s daughter', 'great-niece');
case 'sibdauchi': return i18n::translate_c('sibling\'s daughter\'s child', 'great-nephew/niece');
case 'sibchison': return i18n::translate_c('sibling\'s child\'s son', 'great-nephew');
case 'sibchidau': return i18n::translate_c('sibling\'s child\'s daughter', 'great-niece');
case 'sibchichi': return i18n::translate_c('sibling\'s child\'s child', 'great-nephew/niece');
case 'daudaudau': return i18n::translate_c('daughter\'s daughter\'s daughter', 'great-granddaughter');
case 'daudauson': return i18n::translate_c('daughter\'s daughter\'s son', 'great-grandson');
case 'daudauchi': return i18n::translate_c('daughter\'s daughter\'s child', 'great-grandchild');
case 'dausondau': return i18n::translate_c('daughter\'s son\'s daughter', 'great-granddaughter');
case 'dausonson': return i18n::translate_c('daughter\'s son\'s son', 'great-grandson');
case 'dausonchi': return i18n::translate_c('daughter\'s son\'s child', 'great-grandchild');
case 'dauchidau': return i18n::translate_c('daughter\'s child\'s daughter', 'great-granddaughter');
case 'dauchison': return i18n::translate_c('daughter\'s child\'s son', 'great-grandson');
case 'dauchichi': return i18n::translate_c('daughter\'s child\'s child', 'great-grandchild');
case 'sondaudau': return i18n::translate_c('son\'s daughter\'s daughter', 'great-granddaughter');
case 'sondauson': return i18n::translate_c('son\'s daughter\'s son', 'great-grandson');
case 'sondauchi': return i18n::translate_c('son\'s daughter\'s child', 'great-grandchild');
case 'sonsondau': return i18n::translate_c('son\'s son\'s daughter', 'great-granddaughter');
case 'sonsonson': return i18n::translate_c('son\'s son\'s son', 'great-grandson');
case 'sonsonchi': return i18n::translate_c('son\'s son\'s child', 'great-grandchild');
case 'sonchidau': return i18n::translate_c('son\'s child\'s daughter', 'great-granddaughter');
case 'sonchison': return i18n::translate_c('son\'s child\'s son', 'great-grandson');
case 'sonchichi': return i18n::translate_c('son\'s child\'s child', 'great-grandchild');
case 'chidaudau': return i18n::translate_c('child\'s daughter\'s daughter', 'great-granddaughter');
case 'chidauson': return i18n::translate_c('child\'s daughter\'s son', 'great-grandson');
case 'chidauchi': return i18n::translate_c('child\'s daughter\'s child', 'great-grandchild');
case 'chisondau': return i18n::translate_c('child\'s son\'s daughter', 'great-granddaughter');
case 'chisonson': return i18n::translate_c('child\'s son\'s son', 'great-grandson');
case 'chisonchi': return i18n::translate_c('child\'s son\'s child', 'great-grandchild');
case 'chichidau': return i18n::translate_c('child\'s child\'s daughter', 'great-granddaughter');
case 'chichison': return i18n::translate_c('child\'s child\'s son', 'great-grandson');
case 'chichichi': return i18n::translate_c('child\'s child\'s child', 'great-grandchild');
case 'mothusson': return i18n::translate_c('mother\'s husband\'s son', 'step-brother');
case 'mothusdau': return i18n::translate_c('mother\'s husband\'s daughter', 'step-sister');
case 'mothuschi': return i18n::translate_c('mother\'s husband\'s child', 'step-sibling');
case 'fatwifson': return i18n::translate_c('father\'s wife\'s son', 'step-brother');
case 'fatwifdau': return i18n::translate_c('father\'s wife\'s daughter', 'step-sister');
case 'fatwifchi': return i18n::translate_c('father\'s wife\'s child', 'step-sibling');
case 'parsposon': return i18n::translate_c('parent\'s spouse\'s son', 'step-brother');
case 'parspodau': return i18n::translate_c('parent\'s spouse\'s daughter', 'step-sister');
case 'parspochi': return i18n::translate_c('parent\'s spouse\'s child', 'step-sibling');
case 'motmotsis': return i18n::translate_c('mother\'s mother\'s sister', 'great-aunt');
case 'motmotbro': return i18n::translate_c('mother\'s mother\'s brother', 'great-uncle');
case 'motmotsib': return i18n::translate_c('mother\'s mother\'s sibling', 'great-aunt/uncle');
case 'motfatsis': return i18n::translate_c('mother\'s father\'s sister', 'great-aunt');
case 'motfatbro': return i18n::translate_c('mother\'s father\'s brother', 'great-uncle');
case 'motfatsib': return i18n::translate_c('mother\'s father\'s sibling', 'great-aunt/uncle');
case 'motparsis': return i18n::translate_c('mother\'s parent\'s sister', 'great-aunt');
case 'motparbro': return i18n::translate_c('mother\'s parent\'s brother', 'great-uncle');
case 'motparsib': return i18n::translate_c('mother\'s parent\'s sibling', 'great-aunt/uncle');
case 'fatmotsis': return i18n::translate_c('father\'s mother\'s sister', 'great-aunt');
case 'fatmotbro': return i18n::translate_c('father\'s mother\'s brother', 'great-uncle');
case 'fatmotsib': return i18n::translate_c('father\'s mother\'s sibling', 'great-aunt/uncle');
case 'fatfatsis': return i18n::translate_c('father\'s father\'s sister', 'great-aunt');
case 'fatfatbro': return i18n::translate_c('father\'s father\'s brother', 'great-uncle');
case 'fatfatsib': return i18n::translate_c('father\'s father\'s sibling', 'great-aunt/uncle');
case 'fatparsis': return i18n::translate_c('father\'s parent\'s sister', 'great-aunt');
case 'fatparbro': return i18n::translate_c('father\'s parent\'s brother', 'great-uncle');
case 'fatparsib': return i18n::translate_c('father\'s parent\'s sibling', 'great-aunt/uncle');
case 'parmotsis': return i18n::translate_c('parent\'s mother\'s sister', 'great-aunt');
case 'parmotbro': return i18n::translate_c('parent\'s mother\'s brother', 'great-uncle');
case 'parmotsib': return i18n::translate_c('parent\'s mother\'s sibling', 'great-aunt/uncle');
case 'parfatsis': return i18n::translate_c('parent\'s father\'s sister', 'great-aunt');
case 'parfatbro': return i18n::translate_c('parent\'s father\'s brother', 'great-uncle');
case 'parfatsib': return i18n::translate_c('parent\'s father\'s sibling', 'great-aunt/uncle');
case 'parparsis': return i18n::translate_c('parent\'s parent\'s sister', 'great-aunt');
case 'parparbro': return i18n::translate_c('parent\'s parent\'s brother', 'great-uncle');
case 'parparsib': return i18n::translate_c('parent\'s parent\'s sibling', 'great-aunt/uncle');
case 'brodauhus': return i18n::translate_c('brother\'s daughter\'s husband', 'nephew-in-law');
case 'brosonwif': return i18n::translate_c('brother\'s son\'s wife', 'niece-in-law');
case 'sisdauhus': return i18n::translate_c('sisters\'s daughter\'s husband', 'nephew-in-law');
case 'sissonwif': return i18n::translate_c('sisters\'s son\'s wife', 'niece-in-law');
case 'sibdauhus': return i18n::translate_c('sibling\'s daughter\'s husband', 'nephew-in-law');
case 'sibsonwif': return i18n::translate_c('sibling\'s son\'s wife', 'niece-in-law');
case 'motbrowif': return i18n::translate_c('mother\'s brother\'s wife', 'aunt');
case 'motsishus': return i18n::translate_c('mother\'s sister\'s husband', 'uncle');
case 'fatbrowif': return i18n::translate_c('father\'s brother\'s wife', 'aunt');
case 'fatsishus': return i18n::translate_c('father\'s sister\'s husband', 'uncle');
case 'parbrowif': return i18n::translate_c('parent\'s brother\'s wife', 'aunt');
case 'parsishus': return i18n::translate_c('parent\'s sister\'s husband', 'uncle');
case 'motbroson': return i18n::translate_c('mother\'s brother\'s son', 'cousin');
case 'motbrodau': return i18n::translate_c('mother\'s brother\'s daughter', 'cousin');
case 'motbrochi': return i18n::translate_c('mother\'s brother\'s child', 'cousin');
case 'fatbroson': return i18n::translate_c('father\'s brother\'s son', 'cousin');
case 'fatbrodau': return i18n::translate_c('father\'s brother\'s daughter', 'cousin');
case 'fatbrochi': return i18n::translate_c('father\'s brother\'s child', 'cousin');
case 'motsisson': return i18n::translate_c('mother\'s sister\'s son', 'cousin');
case 'motsisdau': return i18n::translate_c('mother\'s sister\'s daughter', 'cousin');
case 'motsischi': return i18n::translate_c('mother\'s sister\'s child', 'cousin');
case 'fatsisson': return i18n::translate_c('father\'s sister\'s son', 'cousin');
case 'fatsisdau': return i18n::translate_c('father\'s sister\'s daughter', 'cousin');
case 'fatsischi': return i18n::translate_c('father\'s sister\'s child', 'cousin');
}
// Look for generic/pattern relationships.
// TODO: these are heavily based on english relationship names.
// We need feedback from other languages to improve this.
// Dutch has special names for 8 generations of great-great-..., so these need explicit naming
if (preg_match('/^((?:mot|fat|par)+)(bro|sis|sib)$/', $path, $match)) {
$up=strlen($match[1])/3;
$last=substr($path, -3, 3);
switch ($up) {
case 3:
switch ($last) {
case 'bro': return i18n::translate('great-great-uncle');
case 'sis': return i18n::translate('great-great-aunt');
case 'sib': return i18n::translate('great-great-aunt/uncle');
}
break;
case 4:
switch ($last) {
case 'bro': return i18n::translate('great-great-great-uncle');
case 'sis': return i18n::translate('great-great-great-aunt');
case 'sib': return i18n::translate('great-great-great-aunt/uncle');
}
break;
case 5:
switch ($last) {
case 'bro': return i18n::translate('great x4 uncle');
case 'sis': return i18n::translate('great x4 aunt');
case 'sib': return i18n::translate('great x4 aunt/uncle');
}
break;
case 6:
switch ($last) {
case 'bro': return i18n::translate('great x5 uncle');
case 'sis': return i18n::translate('great x5 aunt');
case 'sib': return i18n::translate('great x5 aunt/uncle');
}
break;
case 7:
switch ($last) {
case 'bro': return i18n::translate('great x6 uncle');
case 'sis': return i18n::translate('great x6 aunt');
case 'sib': return i18n::translate('great x6 aunt/uncle');
}
break;
case 8:
switch ($last) {
case 'bro': return i18n::translate('great x7 uncle');
case 'sis': return i18n::translate('great x7 aunt');
case 'sib': return i18n::translate('great x7 aunt/uncle');
}
break;
default:
// Different languages have different rules for naming generations.
// An english great x12 uncle is a danish great x10 uncle.
//
// Need to find out which languages use which rules.
switch (WT_LOCALE) {
case 'da':
switch ($last) {
case 'bro': return i18n::translate('great x%d uncle', $up-4);
case 'sis': return i18n::translate('great x%d aunt', $up-4);
case 'sib': return i18n::translate('great x%d aunt/uncle', $up-4);
}
case 'it': // Source: Michele Locati
case 'en':
default:
switch ($last) {
case 'bro': // I18N: if you need a different number for %d, contact the developers, as a code-change is required
return i18n::translate('great x%d uncle', $up-2);
case 'sis': return i18n::translate('great x%d aunt', $up-2);
case 'sib': return i18n::translate('great x%d aunt/uncle', $up-2);
}
}
}
}
if (preg_match('/^(?:bro|sis|sib)((?:son|dau|chi)+)$/', $path, $match)) {
$down=strlen($match[1])/3+1; // Add one,as we count generations from the common ancestor
$last=substr($path, -3, 3);
switch ($down) {
case 4:
switch ($last) {
case 'son': return i18n::translate('great-great-nephew');
case 'dau': return i18n::translate('great-great-niece');
case 'chi': return i18n::translate('great-great-nephew/niece');
}
case 5:
switch ($last) {
case 'son': return i18n::translate('great-great-great-nephew');
case 'dau': return i18n::translate('great-great-great-niece');
case 'chi': return i18n::translate('great-great-great-nephew/niece');
}
case 6:
switch ($last) {
case 'son': return i18n::translate('great-great-great-great-nephew');
case 'dau': return i18n::translate('great-great-great-great-niece');
case 'chi': return i18n::translate('great-great-great-great-nephew/niece');
}
case 7:
switch ($last) {
case 'son': return i18n::translate('great-great-great-great-great-nephew');
case 'dau': return i18n::translate('great-great-great-great-great-niece');
case 'chi': return i18n::translate('great-great-great-great-great-nephew/niece');
}
default:
// Different languages have different rules for naming generations.
// An english great x12 nephew is a polish great x11 nephew.
//
// Need to find out which languages use which rules.
switch (WT_LOCALE) {
case 'pl': // Source: Lukasz Wilenski
switch ($last) {
case 'son': // I18N: if you need a different number for %d, contact the developers, as a code-change is required
return i18n::translate('great x%d nephew', $down-1);
case 'dau': return i18n::translate('great x%d niece', $down-1);
case 'chi': return i18n::translate('great x%d nephew/niece', $down-1);
}
case 'it': // Source: Michele Locati.
case 'en':
default:
switch ($last) {
case 'son': // I18N: if you need a different number for %d, contact the developers, as a code-change is required
return i18n::translate('great x%d nephew', $down-2);
case 'dau': return i18n::translate('great x%d niece', $down-2);
case 'chi': return i18n::translate('great x%d nephew/niece', $down-2);
}
}
}
}
if (preg_match('/^((?:mot|fat|par)*)$/', $path, $match)) {
$up=strlen($match[1])/3;
$last=substr($path, -3, 3);
switch ($up) {
case 4:
switch ($last) {
case 'mot': return i18n::translate('great-great-grandmother');
case 'fat': return i18n::translate('great-great-grandfather');
case 'par': return i18n::translate('great-great-grandparent');
}
break;
case 5:
switch ($last) {
case 'mot': return i18n::translate('great-great-great-grandmother');
case 'fat': return i18n::translate('great-great-great-grandfather');
case 'par': return i18n::translate('great-great-great-grandparent');
}
break;
case 6:
switch ($last) {
case 'mot': return i18n::translate('great x4 grandmother');
case 'fat': return i18n::translate('great x4 grandfather');
case 'par': return i18n::translate('great x4 grandparent');
}
break;
case 7:
switch ($last) {
case 'mot': return i18n::translate('great x5 grandmother');
case 'fat': return i18n::translate('great x5 grandfather');
case 'par': return i18n::translate('great x5 grandparent');
}
break;
case 8:
switch ($last) {
case 'mot': return i18n::translate('great x6 grandmother');
case 'fat': return i18n::translate('great x6 grandfather');
case 'par': return i18n::translate('great x6 grandparent');
}
break;
case 9:
switch ($last) {
case 'mot': return i18n::translate('great x7 grandmother');
case 'fat': return i18n::translate('great x7 grandfather');
case 'par': return i18n::translate('great x7 grandparent');
}
break;
default:
// Different languages have different rules for naming generations.
// An english great x12 grandfather is a danish great x11 grandfather.
//
// Need to find out which languages use which rules.
switch (WT_LOCALE) {
case 'da': // Source: Patrick Sorensen
switch ($last) {
case 'mot': return i18n::translate('great x%d grandmother', $up-3);
case 'fat': return i18n::translate('great x%d grandfather', $up-3);
case 'par': return i18n::translate('great x%d grandparent', $up-3);
}
case 'it': // Source: Michele Locati
switch ($last) {
case 'mot': return i18n::translate('great x%d grandmother', $up);
case 'fat': return i18n::translate('great x%d grandfather', $up);
case 'par': return i18n::translate('great x%d grandparent', $up);
}
case 'en':
default:
switch ($last) {
case 'mot': // I18N: if you need a different number for %d, contact the developers, as a code-change is required
return i18n::translate('great x%d grandmother', $up-2);
case 'fat': return i18n::translate('great x%d grandfather', $up-2);
case 'par': return i18n::translate('great x%d grandparent', $up-2);
}
}
}
}
if (preg_match('/^((?:son|dau|chi)*)$/', $path, $match)) {
$up=strlen($match[1])/3;
$last=substr($path, -3, 3);
switch ($up) {
case 4:
switch ($last) {
case 'son': return i18n::translate('great-great-grandson');
case 'dau': return i18n::translate('great-great-granddaughter');
case 'chi': return i18n::translate('great-great-grandchild');
}
break;
case 5:
switch ($last) {
case 'son': return i18n::translate('great-great-great-grandson');
case 'dau': return i18n::translate('great-great-great-granddaughter');
case 'chi': return i18n::translate('great-great-great-grandchild');
}
break;
case 6:
switch ($last) {
case 'son': return i18n::translate('great x4 grandson');
case 'dau': return i18n::translate('great x4 granddaughter');
case 'chi': return i18n::translate('great x4 grandchild');
}
break;
case 7:
switch ($last) {
case 'son': return i18n::translate('great x5 grandson');
case 'dau': return i18n::translate('great x5 granddaughter');
case 'chi': return i18n::translate('great x5 grandchild');
}
break;
case 8:
switch ($last) {
case 'son': return i18n::translate('great x6 grandson');
case 'dau': return i18n::translate('great x6 granddaughter');
case 'chi': return i18n::translate('great x6 grandchild');
}
break;
case 9:
switch ($last) {
case 'son': return i18n::translate('great x7 grandson');
case 'dau': return i18n::translate('great x7 granddaughter');
case 'chi': return i18n::translate('great x7 grandchild');
}
break;
default:
// Different languages have different rules for naming generations.
// An english great x12 grandson is a danish great x11 grandson.
//
// Need to find out which languages use which rules.
switch (WT_LOCALE) {
case 'da': // Source: Patrick Sorensen
switch ($last) {
case 'mot': return i18n::translate('great x%d grandson', $up-3);
case 'fat': return i18n::translate('great x%d granddaughter', $up-3);
case 'par': return i18n::translate('great x%d grandchild', $up-3);
}
case 'en':
case 'it': // Source: Michele Locati
default:
switch ($last) {
case 'son': // I18N: if you need a different number for %d, contact the developers, as a code-change is required
return i18n::translate('great x%d grandson', $up-2);
case 'dau': return i18n::translate('great x%d granddaughter', $up-2);
case 'chi': return i18n::translate('great x%d grandchild', $up-2);
}
}
}
}
if (preg_match('/^((?:mot|fat|par)+)(?:bro|sis|sib)((?:son|dau|chi)+)$/', $path, $match)) {
$up =strlen($match[1])/3;
$down=strlen($match[2])/3;
$last=substr($path, -3, 3);
// Different languages have different rules for naming cousins. For example,
// an english "second cousin once removed" is a polish "cousin of 7th degree".
//
// Need to find out which languages use which rules.
switch (WT_LOCALE) {
case 'pl': // Source: Lucasz Wilenski
switch ($last) {
case 'son': return /* I18N: %s is "first", "second", ... */ i18n::translate_c('MALE', 'cousin of the %s degree', i18n::ordinal_word($up+$down+2));
case 'dau': return /* I18N: %s is "first", "second", ... */ i18n::translate_c('FEMALE', 'cousin of the %s degree', i18n::ordinal_word($up+$down+2));
case 'chi': return /* I18N: %s is "first", "second", ... */ i18n::translate('cousin of the %s degree', i18n::ordinal_word($up+$down+2));
}
break;
case 'it':
// Source: Michele Locati. See italian_cousins_names.zip
// http://webtrees.net/forums/8-translation/1200-great-xn-grandparent?limit=6&start=6
switch ($last) {
case 'son': return /* I18N: %s is "first", "second", ... */ i18n::translate_c('MALE', 'cousin of the %s degree', i18n::ordinal_word($up+$down-3));
case 'dau': return /* I18N: %s is "first", "second", ... */ i18n::translate_c('FEMALE', 'cousin of the %s degree', i18n::ordinal_word($up+$down-3));
case 'chi': return /* I18N: %s is "first", "second", ... */ i18n::translate('cousin of the %s degree', i18n::ordinal_word($up+$down-3));
}
break;
case 'en': // See: http://en.wikipedia.org/wiki/File:CousinTree.svg
default:
if ($up==$down) {
switch ($last) {
case 'son': return i18n::translate_c('MALE', '%s cousin', i18n::ordinal_word($up-1));
case 'dau': return i18n::translate_c('FEMALE', '%s cousin', i18n::ordinal_word($up-1));
case 'chi': return i18n::translate('%s cousin', i18n::ordinal_word($up-1));
}
} else {
$removed=abs($down-$up);
switch ($last) {
case 'son':
return i18n::plural(
'%1$s male cousin, %2$d time removed', '%1$s male cousin, %2$d times removed',
$removed, i18n::ordinal_word(min($up, $down)), $removed
);
case 'dau':
return i18n::plural(
'%1$s female cousin, %2$d time removed', '%1$s female cousin, %2$d times removed',
$removed, i18n::ordinal_word(min($up, $down)), $removed
);
case 'chi': return i18n::plural('%1$s cousin, %2$d time removed', '%1$s cousin, %2$d times removed',
$removed, i18n::ordinal_word(min($up, $down)), $removed
);
}
}
break;
}
}
// TODO: break the relationship down into sub-relationships. e.g. cousin's cousin.
// We don't have a specific name for this relationship, and we can't match it with a pattern.
// Just spell it out.
// TODO: long relationships are a bit ridiculous - although tecnically correct.
// Perhaps translate long paths as "a distant blood relative", or "a distant relative by marriage"
switch (substr($path, -3, 3)) {
case 'mot': $relationship=i18n::translate('mother' ); break;
case 'fat': $relationship=i18n::translate('father' ); break;
case 'par': $relationship=i18n::translate('parent' ); break;
case 'hus': $relationship=i18n::translate('husband' ); break;
case 'wif': $relationship=i18n::translate('wife' ); break;
case 'spo': $relationship=i18n::translate('spouse' ); break;
case 'bro': $relationship=i18n::translate('brother' ); break;
case 'sis': $relationship=i18n::translate('sister' ); break;
case 'sib': $relationship=i18n::translate('sibling' ); break;
case 'son': $relationship=i18n::translate('son' ); break;
case 'dau': $relationship=i18n::translate('daughter'); break;
case 'chi': $relationship=i18n::translate('child' ); break;
}
while (($path=substr($path, 0, strlen($path)-3))!='') {
switch (substr($path, -3, 3)) {
// I18N: These strings are used to build paths of relationships, such as "father's wife's husband's brother"
case 'mot': $relationship=i18n::translate('mother\'s %s', $relationship); break;
case 'fat': $relationship=i18n::translate('father\'s %s', $relationship); break;
case 'par': $relationship=i18n::translate('parent\'s %s', $relationship); break;
case 'hus': $relationship=i18n::translate('husband\'s %s', $relationship); break;
case 'wif': $relationship=i18n::translate('wife\'s %s', $relationship); break;
case 'spo': $relationship=i18n::translate('spouse\'s %s', $relationship); break;
case 'bro': $relationship=i18n::translate('brother\'s %s', $relationship); break;
case 'sis': $relationship=i18n::translate('sister\'s %s', $relationship); break;
case 'sib': $relationship=i18n::translate('sibling\'s %s', $relationship); break;
case 'son': $relationship=i18n::translate('son\'s %s', $relationship); break;
case 'dau': $relationship=i18n::translate('daughter\'s %s', $relationship); break;
case 'chi': $relationship=i18n::translate('child\'s %s', $relationship); break;
}
}
return $relationship;
}
/**
* get theme names
*
* function to get the names of all of the themes as an array
* it searches the themes directory and reads the name from the theme_name variable
* in the theme.php file.
* @return array and array of theme names and their corresponding directory
*/
function get_theme_names() {
$themes = array();
$d = dir("themes");
while (false !== ($entry = $d->read())) {
if ($entry{0}!="." && $entry!="CVS" && !stristr($entry, "svn") && is_dir(WT_ROOT.'themes/'.$entry) && file_exists(WT_ROOT.'themes/'.$entry.'/theme.php')) {
$themefile = implode("", file(WT_ROOT.'themes/'.$entry.'/theme.php'));
$tt = preg_match("/theme_name\s*=\s*\"(.*)\";/", $themefile, $match);
if ($tt>0)
$themename = trim($match[1]);
else
$themename = "themes/$entry";
$themes[$themename] = "themes/$entry/";
}
}
$d->close();
uksort($themes, "utf8_strcasecmp");
return $themes;
}
/**
* decode a filename
*
* windows doesn't use UTF-8 for its file system so we have to decode the filename
* before it can be used on the filesystem
*/
function filename_decode($filename) {
if (DIRECTORY_SEPARATOR=='\\')
return utf8_decode($filename);
else
return $filename;
}
/**
* encode a filename
*
* windows doesn't use UTF-8 for its file system so we have to encode the filename
* before it can be used in PGV
*/
function filename_encode($filename) {
if (DIRECTORY_SEPARATOR=='\\')
return utf8_encode($filename);
else
return $filename;
}
////////////////////////////////////////////////////////////////////////////////
// Remove empty and duplicate values from a URL query string
////////////////////////////////////////////////////////////////////////////////
function normalize_query_string($query) {
$components=array();
foreach (preg_split('/(^\?|\&(amp;)*)/', urldecode($query), -1, PREG_SPLIT_NO_EMPTY) as $component)
if (strpos($component, '=')!==false) {
list ($key, $data)=explode('=', $component, 2);
if (!empty($data)) $components[$key]=$data;
}
$new_query='';
foreach ($components as $key=>$data)
$new_query.=(empty($new_query)?'?':'&').$key.'='.$data;
return $new_query;
}
function getfilesize($bytes) {
if ($bytes>=1099511627776) {
return round($bytes/1099511627776, 2)." TB";
}
if ($bytes>=1073741824) {
return round($bytes/1073741824, 2)." GB";
}
if ($bytes>=1048576) {
return round($bytes/1048576, 2)." MB";
}
if ($bytes>=1024) {
return round($bytes/1024, 2)." KB";
}
return $bytes." B";
}
/**
* array merge function for PGV
* the PHP array_merge function will reindex all numerical indexes
* This function should only be used for associative arrays
* @param array $array1
* @param array $array2
*/
function pgv_array_merge($array1, $array2) {
foreach ($array2 as $key=>$value) {
$array1[$key] = $value;
}
return $array1;
}
/**
* checks if the value is in an array recursively
* @param string $needle
* @param array $haystack
*/
function in_arrayr($needle, $haystack) {
foreach ($haystack as $v) {
if ($needle == $v) return true;
else if (is_array($v)) {
if (in_arrayr($needle, $v) === true) return true;
}
}
return false;
}
/**
* function to build an URL querystring from GET or POST variables
* @return string
*/
function get_query_string() {
$qstring = "";
if (!empty($_GET)) {
foreach ($_GET as $key => $value) {
if ($key != "view") {
if (!is_array($value)) {
$qstring .= "{$key}={$value}&";
} else {
foreach ($value as $k=>$v) {
$qstring .= "{$key}[{$k}]={$v}&";
}
}
}
}
} else {
if (!empty($_POST)) {
foreach ($_POST as $key => $value) {
if ($key != "view") {
if (!is_array($value)) {
$qstring .= "{$key}={$value}&";
} else {
foreach ($value as $k=>$v) {
if (!is_array($v)) {
$qstring .= "{$key}[{$k}]={$v}&";
}
}
}
}
}
}
}
$qstring = rtrim($qstring, "&"); // Remove trailing "&"
return encode_url($qstring);
}
//This function works with a specified generation limit. It will completely fill
//the pdf witout regard to if a known person exists in each generation.
//ToDo: If a known individual is found in a generation, add prior empty positions
//and add remaining empty spots automatically.
function add_ancestors(&$list, $pid, $children=false, $generations=-1, $show_empty=false) {
$total_num_skipped = 0;
$skipped_gen = 0;
$num_skipped = 0;
$genlist = array($pid);
$list[$pid]->generation = 1;
while (count($genlist)>0) {
$id = array_shift($genlist);
if (strpos($id, "empty")===0) continue; // id can be something like "empty7"
$person = Person::getInstance($id);
$famids = $person->getChildFamilies();
if (count($famids)>0) {
if ($show_empty) {
for ($i=0;$i<$num_skipped;$i++) {
$list["empty" . $total_num_skipped] = new Person('');
$list["empty" . $total_num_skipped]->generation = $list[$id]->generation+1;
array_push($genlist, "empty" . $total_num_skipped);
$total_num_skipped++;
}
}
$num_skipped = 0;
foreach ($famids as $famid => $family) {
$husband = $family->getHusband();
$wife = $family->getWife();
if ($husband) {
$list[$husband->getXref()] = $husband;
$list[$husband->getXref()]->generation = $list[$id]->generation+1;
} elseif ($show_empty) {
$list["empty" . $total_num_skipped] = new Person('');
$list["empty" . $total_num_skipped]->generation = $list[$id]->generation+1;
}
if ($wife) {
$list[$wife->getXref()] = $wife;
$list[$wife->getXref()]->generation = $list[$id]->generation+1;
} elseif ($show_empty) {
$list["empty" . $total_num_skipped] = new Person('');
$list["empty" . $total_num_skipped]->generation = $list[$id]->generation+1;
}
if ($generations == -1 || $list[$id]->generation+1 < $generations) {
$skipped_gen = $list[$id]->generation+1;
if ($husband) {
array_push($genlist, $husband->getXref());
} elseif ($show_empty) {
array_push($genlist, "empty" . $total_num_skipped);
}
if ($wife) {
array_push($genlist, $wife->getXref());
} elseif ($show_empty) {
array_push($genlist, "empty" . $total_num_skipped);
}
}
$total_num_skipped++;
if ($children) {
$childs = $family->getChildren();
foreach($childs as $child) {
$list[$child->getXref()] = $child;
if (isset($list[$id]->generation))
$list[$child->getXref()]->generation = $list[$id]->generation;
else
$list[$child->getXref()]->generation = 1;
}
}
}
} else
if ($show_empty) {
if ($skipped_gen > $list[$id]->generation) {
$list["empty" . $total_num_skipped] = new Person('');
$list["empty" . $total_num_skipped]->generation = $list[$id]->generation+1;
$total_num_skipped++;
$list["empty" . $total_num_skipped] = new Person('');
$list["empty" . $total_num_skipped]->generation = $list[$id]->generation+1;
array_push($genlist, "empty" . ($total_num_skipped - 1));
array_push($genlist, "empty" . $total_num_skipped);
$total_num_skipped++;
} else
$num_skipped += 2;
}
}
}
//--- copied from class_reportpdf.php
function add_descendancy(&$list, $pid, $parents=false, $generations=-1) {
$person = Person::getInstance($pid);
if ($person==null) return;
if (!isset($list[$pid])) {
$list[$pid] = $person;
}
if (!isset($list[$pid]->generation)) {
$list[$pid]->generation = 0;
}
$famids = $person->getSpouseFamilies();
if (count($famids)>0) {
foreach ($famids as $famid => $family) {
if ($family) {
if ($parents) {
$husband = $family->getHusband();
$wife = $family->getWife();
if ($husband) {
$list[$husband->getXref()] = $husband;
if (isset($list[$pid]->generation))
$list[$husband->getXref()]->generation = $list[$pid]->generation-1;
else
$list[$husband->getXref()]->generation = 1;
}
if ($wife) {
$list[$wife->getXref()] = $wife;
if (isset($list[$pid]->generation))
$list[$wife->getXref()]->generation = $list[$pid]->generation-1;
else
$list[$wife->getXref()]->generation = 1;
}
}
$children = $family->getChildren();
foreach($children as $child) {
if ($child) {
$list[$child->getXref()] = $child;
if (isset($list[$pid]->generation))
$list[$child->getXref()]->generation = $list[$pid]->generation+1;
else
$list[$child->getXref()]->generation = 2;
}
}
if ($generations == -1 || $list[$pid]->generation+1 < $generations) {
foreach($children as $child) {
add_descendancy($list, $child->getXref(), $parents, $generations); // recurse on the childs family
}
}
}
}
}
}
/**
* get the next available xref
* calculates the next available XREF id for the given type of record
* @param string $type the type of record, defaults to 'INDI'
* @return string
*/
function get_new_xref($type='INDI', $ged_id=WT_GED_ID) {
global $SOURCE_ID_PREFIX, $REPO_ID_PREFIX, $MEDIA_ID_PREFIX, $FAM_ID_PREFIX, $GEDCOM_ID_PREFIX;
switch ($type) {
case "INDI":
$prefix = $GEDCOM_ID_PREFIX;
break;
case "FAM":
$prefix = $FAM_ID_PREFIX;
break;
case "OBJE":
$prefix = $MEDIA_ID_PREFIX;
break;
case "SOUR":
$prefix = $SOURCE_ID_PREFIX;
break;
case "REPO":
$prefix = $REPO_ID_PREFIX;
break;
default:
$prefix = $type{0};
break;
}
$num=
WT_DB::prepare("SELECT next_id FROM `##next_id` WHERE record_type=? AND gedcom_id=?")
->execute(array($type, $ged_id))
->fetchOne();
// TODO? If a gedcom file contains *both* inline and object based media, then
// we could be generating an XREF that we will find later. Need to scan the
// entire gedcom for them?
if (is_null($num)) {
$num = 1;
WT_DB::prepare("INSERT INTO `##next_id` (gedcom_id, record_type, next_id) VALUES(?, ?, 1)")
->execute(array($ged_id, $type));
}
//-- make sure this number has not already been used
if ($num>=2147483647 || $num<=0) { // Popular databases are only 32 bits (signed)
$num=1;
}
while (find_gedcom_record($prefix.$num, $ged_id, true)) {
++$num;
if ($num>=2147483647 || $num<=0) { // Popular databases are only 32 bits (signed)
$num=1;
}
}
//-- the key is the prefix and the number
$key = $prefix.$num;
//-- update the next id number in the DB table
WT_DB::prepare("UPDATE `##next_id` SET next_id=? WHERE record_type=? AND gedcom_id=?")
->execute(array($num+1, $type, $ged_id));
return $key;
}
/**
* check if the given string has UTF-8 characters
*
*/
function has_utf8($string) {
$len = strlen($string);
for ($i=0; $i<$len; $i++) {
$letter = substr($string, $i, 1);
$ord = ord($letter);
if ($ord==95 || $ord>=195)
return true;
}
return false;
}
/**
* determines whether the passed in filename is a link to an external source (i.e. contains '://')
*/
function isFileExternal($file) {
return strpos($file, '://') !== false;
}
/*
* Encrypt the input string
*
* This function is used when a file name needs to be passed to another script by means of the
* GET method. This method passes parameters to the script through the URL that launches the
* script.
*
* File names could themselves be legitimate URLs. These legitimate URLs would normally be
* killed by the hacker detection code in "includes/session_spider.php". This method avoids
* that problem.
*
*/
function encrypt($string, $key='') {
if (empty($key)) $key = session_id();
$result = '';
for($i=0; $i 255) $newOrd -= 256; // Make sure we stay within the 8-bit code table
$result .= chr($newOrd);
}
$result = '*'.strtr(base64_encode($result), '+/=', '-_#'); // Avoid characters that mess up URLs
return $result;
}
/*
* Decrypt the input string
*
* See above.
*
*/
function decrypt($string, $key='') {
if (empty($key)) $key = session_id();
if (substr($string, 0, 1)!='*') return $string; // Input is not a valid encrypted string
$string = base64_decode(strtr(substr($string, 1), '-_#', '+/='));
$result = '';
for($i=0; $i';
}
break 2;
}
}
// Lightbox is not installed or Lightbox is not appropriate for this media type
switch ($type) {
case 'url_flv':
$url = "javascript:;\" onclick=\" var winflv = window.open('".encode_url('js/jw_player/flvVideo.php?flvVideo='.($fileName)) . "', 'winflv', 'width=500, height=392, left=600, top=200'); if (window.focus) {winflv.focus();}";
break 2;
case 'local_flv':
$url = "javascript:;\" onclick=\" var winflv = window.open('".encode_url('js/jw_player/flvVideo.php?flvVideo='.(WT_SERVER_NAME.WT_SCRIPT_PATH.$fileName)) . "', 'winflv', 'width=500, height=392, left=600, top=200'); if (window.focus) {winflv.focus();}";
break 2;
case 'url_wmv':
$url = "javascript:;\" onclick=\" var winwmv = window.open('".encode_url('js/jw_player/wmvVideo.php?wmvVideo='.($fileName)) . "', 'winwmv', 'width=500, height=392, left=600, top=200'); if (window.focus) {winwmv.focus();}";
break 2;
case 'local_wmv':
case 'local_audio':
$url = "javascript:;\" onclick=\" var winwmv = window.open('".encode_url('js/jw_player/wmvVideo.php?wmvVideo='.(WT_SERVER_NAME.WT_SCRIPT_PATH.$fileName)) . "', 'winwmv', 'width=500, height=392, left=600, top=200'); if (window.focus) {winwmv.focus();}";
break 2;
case 'url_image':
$imgsize = findImageSize($fileName);
$imgwidth = $imgsize[0]+40;
$imgheight = $imgsize[1]+150;
$url = "javascript:;\" onclick=\"var winimg = window.open('".encode_url($fileName)."', 'winimg', 'width=".$imgwidth.", height=".$imgheight.", left=200, top=200'); if (window.focus) {winimg.focus();}";
break 2;
case 'url_picasa':
case 'url_page':
case 'url_other':
case 'local_other';
$url = "javascript:;\" onclick=\"var winurl = window.open('".encode_url($fileName)."', 'winurl', 'width=900, height=600, left=200, top=200'); if (window.focus) {winurl.focus();}";
break 2;
case 'local_page':
$url = "javascript:;\" onclick=\"var winurl = window.open('".encode_url(WT_SERVER_NAME.WT_SCRIPT_PATH.$fileName)."', 'winurl', 'width=900, height=600, left=200, top=200'); if (window.focus) {winurl.focus();}";
break 2;
case 'url_streetview':
echo '';
$url = "#";
break 2;
}
if ($USE_MEDIA_VIEWER && $obeyViewerOption) {
$url = encode_url('mediaviewer.php?mid='.$mid);
} else {
$imgsize = findImageSize($fileName);
$imgwidth = $imgsize[0]+40;
$imgheight = $imgsize[1]+150;
$url = "javascript:;\" onclick=\"return openImage('".encode_url(encrypt($fileName))."', $imgwidth, $imgheight);";
}
break;
}
// At this point, $url describes how to handle the image when its thumbnail is clicked
if ($type == 'url_streetview') {
$result['url'] = "#";
} else {
$result['url'] = $url;
}
// -- Determine the correct thumbnail or pseudo-thumbnail
$width = '';
switch ($type) {
case 'url_flv':
$thumb = isset($WT_IMAGES["media"]["flashrem"]) ? $WT_IMAGE_DIR.'/'.$WT_IMAGES["media"]["flashrem"] : 'images/media/flashrem.png';
break;
case 'local_flv':
$thumb = isset($WT_IMAGES["media"]["flash"]) ? $WT_IMAGE_DIR.'/'.$WT_IMAGES["media"]["flash"] : 'images/media/flash.png';
break;
case 'url_wmv':
$thumb = isset($WT_IMAGES["media"]["wmvrem"]) ? $WT_IMAGE_DIR.'/'.$WT_IMAGES["media"]["wmvrem"] : 'images/media/wmvrem.png';
break;
case 'local_wmv':
$thumb = isset($WT_IMAGES["media"]["wmv"]) ? $WT_IMAGE_DIR.'/'.$WT_IMAGES["media"]["wmv"] : 'images/media/wmv.png';
break;
case 'url_picasa':
$thumb = isset($WT_IMAGES["media"]["picasa"]) ? $WT_IMAGE_DIR.'/'.$WT_IMAGES["media"]["picasa"] : 'images/media/picasa.png';
break;
case 'url_page':
case 'url_other':
$thumb = isset($WT_IMAGES["media"]["globe"]) ? $WT_IMAGE_DIR.'/'.$WT_IMAGES["media"]["globe"] : 'images/media/globe.png';
break;
case 'local_page':
$thumb = ($WT_IMAGES["media"]["doc"]) ? $WT_IMAGE_DIR.'/'.$WT_IMAGES["media"]["doc"] : 'images/media/doc.gif';
break;
case 'url_audio':
case 'local_audio':
$thumb = isset($WT_IMAGES["media"]["audio"]) ? $WT_IMAGE_DIR.'/'.$WT_IMAGES["media"]["audio"] : 'images/media/audio.png';
break;
case 'url_streetview':
$thumb = null;
break;
default:
$thumb = $thumbName;
if (substr($type, 0, 4)=='url_') {
$width = ' width="'.$THUMBNAIL_WIDTH.'"';
}
}
// -- Use an overriding thumbnail if one has been provided
// Don't accept any overriding thumbnails that are in the "images" or "themes" directories
if (substr($thumbName, 0, 7)!='images/' && substr($thumbName, 0, 7)!='themes/') {
if ($USE_MEDIA_FIREWALL && $MEDIA_FIREWALL_THUMBS) {
$tempThumbName = get_media_firewall_path($thumbName);
} else {
$tempThumbName = $thumbName;
}
if (file_exists($tempThumbName)) {
$thumb = $thumbName;
}
}
// -- Use the theme-specific media icon if nothing else works
$realThumb = $thumb;
if (substr($type, 0, 6)=='local_' && !file_exists($thumb)) {
if (!$USE_MEDIA_FIREWALL || !$MEDIA_FIREWALL_THUMBS) {
$thumb = $WT_IMAGE_DIR.'/'.$WT_IMAGES['media']['large'];
$realThumb = $thumb;
} else {
$realThumb = get_media_firewall_path($thumb);
if (!file_exists($realThumb)) {
$thumb = $WT_IMAGE_DIR.'/'.$WT_IMAGES['media']['large'];
$realThumb = $thumb;
}
}
$width = '';
}
// At this point, $width, $realThumb, and $thumb describe the thumbnail to be displayed
$result['thumb'] = $thumb;
$result['realThumb'] = $realThumb;
$result['width'] = $width;
return $result;
}
// PHP's native pathinfo() function does not work with filenames that contain UTF8 characters.
// See http://uk.php.net/pathinfo
function pathinfo_utf($path) {
if (empty($path)) {
return array('dirname'=>'', 'basename'=>'', 'extension'=>'', 'filename'=>'');
}
if (strpos($path, '/')!==false) {
$tmp=explode('/', $path);
$basename=end($tmp);
$dirname=substr($path, 0, strlen($path) - strlen($basename) - 1);
} else if (strpos($path, '\\') !== false) {
$tmp=explode('\\', $path);
$basename=end($tmp);
$dirname=substr($path, 0, strlen($path) - strlen($basename) - 1);
} else {
$basename=$path; // We have just a file name
$dirname='.'; // For compatibility with pathinfo()
}
if (strpos($basename, '.')!==false) {
$tmp=explode('.', $path);
$extension=end($tmp);
$filename=substr($basename, 0, strlen($basename) - strlen($extension) - 1);
} else {
$extension='';
$filename=$basename;
}
return array('dirname'=>$dirname, 'basename'=>$basename, 'extension'=>$extension, 'filename'=>$filename);
}
// optional extra file
if (file_exists(WT_ROOT.'includes/functions.extra.php')) {
require WT_ROOT.'includes/functions.extra.php';
}
?>