summaryrefslogtreecommitdiff
path: root/library
diff options
context:
space:
mode:
Diffstat (limited to 'library')
-rw-r--r--library/WT/Controller/AdvancedSearch.php10
-rw-r--r--library/WT/Controller/Ancestry.php4
-rw-r--r--library/WT/Controller/Chart.php4
-rw-r--r--library/WT/Controller/Compact.php12
-rw-r--r--library/WT/Controller/Descendancy.php8
-rw-r--r--library/WT/Controller/Family.php62
-rw-r--r--library/WT/Controller/Familybook.php10
-rw-r--r--library/WT/Controller/Fanchart.php8
-rw-r--r--library/WT/Controller/GedcomRecord.php18
-rw-r--r--library/WT/Controller/Hourglass.php8
-rw-r--r--library/WT/Controller/Individual.php356
-rw-r--r--library/WT/Controller/Lifespan.php16
-rw-r--r--library/WT/Controller/Media.php56
-rw-r--r--library/WT/Controller/Note.php50
-rw-r--r--library/WT/Controller/Page.php13
-rw-r--r--library/WT/Controller/Pedigree.php4
-rw-r--r--library/WT/Controller/Repository.php50
-rw-r--r--library/WT/Controller/Search.php30
-rw-r--r--library/WT/Controller/Source.php50
-rw-r--r--library/WT/Controller/Timeline.php42
-rw-r--r--library/WT/Fact.php (renamed from library/WT/Event.php)289
-rw-r--r--library/WT/Family.php140
-rw-r--r--library/WT/Gedcom/Code/Adop.php4
-rw-r--r--library/WT/Gedcom/Code/Name.php4
-rw-r--r--library/WT/Gedcom/Code/Pedi.php4
-rw-r--r--library/WT/Gedcom/Code/Rela.php4
-rw-r--r--library/WT/Gedcom/Tag.php10
-rw-r--r--library/WT/GedcomRecord.php783
-rw-r--r--library/WT/Individual.php (renamed from library/WT/Person.php)742
-rw-r--r--library/WT/Media.php59
-rw-r--r--library/WT/MenuBar.php8
-rw-r--r--library/WT/Note.php28
-rw-r--r--library/WT/Query/Media.php8
-rw-r--r--library/WT/Query/Name.php8
-rw-r--r--library/WT/Report/Base.php69
-rw-r--r--library/WT/Repository.php11
-rw-r--r--library/WT/Source.php21
-rw-r--r--library/WT/Stats.php54
-rw-r--r--library/phpmailer/class.phpmailer.php1320
-rw-r--r--library/phpmailer/class.smtp.php695
-rw-r--r--library/phpmailer/language/phpmailer.lang-ar.php3
-rw-r--r--library/phpmailer/language/phpmailer.lang-br.php24
-rw-r--r--library/phpmailer/language/phpmailer.lang-ca.php3
-rw-r--r--library/phpmailer/language/phpmailer.lang-ch.php3
-rw-r--r--library/phpmailer/language/phpmailer.lang-cz.php3
-rw-r--r--library/phpmailer/language/phpmailer.lang-de.php3
-rw-r--r--library/phpmailer/language/phpmailer.lang-dk.php3
-rw-r--r--library/phpmailer/language/phpmailer.lang-eo.php24
-rw-r--r--library/phpmailer/language/phpmailer.lang-es.php26
-rw-r--r--library/phpmailer/language/phpmailer.lang-et.php16
-rw-r--r--library/phpmailer/language/phpmailer.lang-fi.php3
-rw-r--r--library/phpmailer/language/phpmailer.lang-fo.php3
-rw-r--r--library/phpmailer/language/phpmailer.lang-fr.php31
-rw-r--r--library/phpmailer/language/phpmailer.lang-he.php25
-rw-r--r--library/phpmailer/language/phpmailer.lang-hu.php37
-rw-r--r--library/phpmailer/language/phpmailer.lang-it.php21
-rw-r--r--library/phpmailer/language/phpmailer.lang-ja.php6
-rw-r--r--library/phpmailer/language/phpmailer.lang-lt.php24
-rw-r--r--library/phpmailer/language/phpmailer.lang-nl.php41
-rw-r--r--library/phpmailer/language/phpmailer.lang-no.php23
-rw-r--r--library/phpmailer/language/phpmailer.lang-pl.php38
-rw-r--r--library/phpmailer/language/phpmailer.lang-ro.php3
-rw-r--r--library/phpmailer/language/phpmailer.lang-ru.php13
-rw-r--r--library/phpmailer/language/phpmailer.lang-se.php3
-rw-r--r--library/phpmailer/language/phpmailer.lang-sk.php25
-rw-r--r--library/phpmailer/language/phpmailer.lang-tr.php28
-rw-r--r--library/phpmailer/language/phpmailer.lang-uk.php24
-rw-r--r--library/phpmailer/language/phpmailer.lang-zh.php3
-rw-r--r--library/phpmailer/language/phpmailer.lang-zh_cn.php3
69 files changed, 2634 insertions, 2900 deletions
diff --git a/library/WT/Controller/AdvancedSearch.php b/library/WT/Controller/AdvancedSearch.php
index cba844cd74..586db82939 100644
--- a/library/WT/Controller/AdvancedSearch.php
+++ b/library/WT/Controller/AdvancedSearch.php
@@ -2,7 +2,7 @@
// Controller for the advanced search page
//
// webtrees: Web based Family History software
-// Copyright (C) 2012 webtrees development team.
+// Copyright (C) 2013 webtrees development team.
//
// Derived from PhpGedView
// Copyright (C) 2002 to 2009 PGV Development Team. All rights reserved.
@@ -202,7 +202,7 @@ class WT_Controller_AdvancedSearch extends WT_Controller_Search {
}
// Dynamic SQL query, plus bind variables
- $sql="SELECT DISTINCT 'INDI' AS type, ind.i_id AS xref, ind.i_file AS ged_id, ind.i_gedcom AS gedrec FROM `##individuals` ind";
+ $sql="SELECT DISTINCT ind.i_id AS xref, ind.i_file AS gedcom_id, ind.i_gedcom AS gedcom FROM `##individuals` ind";
$bind=array();
// Join the following tables
@@ -486,13 +486,13 @@ class WT_Controller_AdvancedSearch extends WT_Controller_Search {
$bind[]=$value;
}
}
- $rows=WT_DB::prepare($sql)->execute($bind)->fetchAll(PDO::FETCH_ASSOC);
+ $rows=WT_DB::prepare($sql)->execute($bind)->fetchAll();
foreach ($rows as $row) {
- $person=WT_Person::getInstance($row);
+ $person=WT_Individual::getInstance($row->xref, $row->gedcom_id, $row->gedcom);
// Check for XXXX:PLAC fields, which were only partially matched by SQL
foreach ($this->fields as $n=>$field) {
if ($this->values[$n] && preg_match('/^('.WT_REGEX_TAG.'):PLAC$/', $field, $match)) {
- if (!preg_match('/\n1 '.$match[1].'(\n[2-9].*)*\n2 PLAC .*'.preg_quote($this->values[$n], '/').'/i', $person->getGedcomRecord())) {
+ if (!preg_match('/\n1 '.$match[1].'(\n[2-9].*)*\n2 PLAC .*'.preg_quote($this->values[$n], '/').'/i', $person->getGedcom())) {
continue 2;
}
}
diff --git a/library/WT/Controller/Ancestry.php b/library/WT/Controller/Ancestry.php
index 6228418cdc..23bafdd5b5 100644
--- a/library/WT/Controller/Ancestry.php
+++ b/library/WT/Controller/Ancestry.php
@@ -2,7 +2,7 @@
// Controller for the ancestry chart
//
// webtrees: Web based Family History software
-// Copyright (C) 2012 webtrees development team.
+// Copyright (C) 2013 webtrees development team.
//
// Derived from PhpGedView
// Copyright (C) 2002 to 2009 PGV Development Team. All rights reserved.
@@ -74,7 +74,7 @@ class WT_Controller_Ancestry extends WT_Controller_Chart {
$pbwidth = $bwidth+12;
$pbheight = $bheight+14;
- if ($this->root && $this->root->canDisplayName()) {
+ if ($this->root && $this->root->canShowName()) {
$this->setPageTitle(
/* I18N: %s is an individual’s name */
WT_I18N::translate('Ancestors of %s', $this->root->getFullName())
diff --git a/library/WT/Controller/Chart.php b/library/WT/Controller/Chart.php
index 6e54c135d7..ce9f1d9726 100644
--- a/library/WT/Controller/Chart.php
+++ b/library/WT/Controller/Chart.php
@@ -35,14 +35,14 @@ class WT_Controller_Chart extends WT_Controller_Page {
$this->rootid = safe_GET_xref('rootid');
if ($this->rootid) {
- $this->root = WT_Person::getInstance($this->rootid);
+ $this->root = WT_Individual::getInstance($this->rootid);
} else {
// Missing rootid parameter? Do something.
$this->root = $this->getSignificantIndividual();
$this->rootid = $this->root->getXref();
}
- if (!$this->root || !$this->root->canDisplayName()) {
+ if (!$this->root || !$this->root->canShowName()) {
header($_SERVER['SERVER_PROTOCOL'].' 403 Forbidden');
$this->error_message=WT_I18N::translate('This individual does not exist or you do not have permission to view it.');
$this->rootid=null;
diff --git a/library/WT/Controller/Compact.php b/library/WT/Controller/Compact.php
index d8b051e248..5bda1695b1 100644
--- a/library/WT/Controller/Compact.php
+++ b/library/WT/Controller/Compact.php
@@ -2,7 +2,7 @@
// Controller for the compact chart
//
// webtrees: Web based Family History software
-// Copyright (C) 2012 webtrees development team.
+// Copyright (C) 2013 webtrees development team.
//
// Derived from PhpGedView
// Copyright (C) 2002 to 2009 PGV Development Team. All rights reserved.
@@ -41,7 +41,7 @@ class WT_Controller_Compact extends WT_Controller_Chart {
// Extract the request parameters
$this->show_thumbs=safe_GET_bool('show_thumbs');
- if ($this->root && $this->root->canDisplayName()) {
+ if ($this->root && $this->root->canShowName()) {
$this->setPageTitle(
/* I18N: %s is an individual’s name */
WT_I18N::translate('Compact tree of %s', $this->root->getFullName())
@@ -55,9 +55,9 @@ class WT_Controller_Compact extends WT_Controller_Chart {
function sosa_person($n) {
global $SHOW_HIGHLIGHT_IMAGES;
- $indi=WT_Person::getInstance($this->treeid[$n]);
+ $indi=WT_Individual::getInstance($this->treeid[$n]);
- if ($indi && $indi->canDisplayName()) {
+ if ($indi && $indi->canShowName()) {
$name=$indi->getFullName();
$addname=$indi->getAddName();
@@ -72,7 +72,7 @@ class WT_Controller_Compact extends WT_Controller_Chart {
if ($addname) $html .= '<br>' . $addname;
$html .= '</a>';
$html .= '<br>';
- if ($indi->canDisplayDetails()) {
+ if ($indi->canShow()) {
$html.='<div class="details1">'.$indi->getLifeSpan().'</div>';
}
} else {
@@ -115,7 +115,7 @@ class WT_Controller_Compact extends WT_Controller_Chart {
}
if ($pid) {
- $indi=WT_Person::getInstance($pid);
+ $indi=WT_Individual::getInstance($pid);
$title=WT_I18N::translate('Compact tree of %s', $indi->getFullName());
$text = '<a class="icon-'.$arrow_dir.'arrow" title="'.strip_tags($title).'" href="?rootid='.$pid;
if ($this->show_thumbs) $text .= "&amp;show_thumbs=".$this->show_thumbs;
diff --git a/library/WT/Controller/Descendancy.php b/library/WT/Controller/Descendancy.php
index f9d07c6977..9ee2c3d733 100644
--- a/library/WT/Controller/Descendancy.php
+++ b/library/WT/Controller/Descendancy.php
@@ -2,7 +2,7 @@
// Controller for the descendancy chart
//
// webtrees: Web based Family History software
-// Copyright (C) 2012 webtrees development team.
+// Copyright (C) 2013 webtrees development team.
//
// Derived from PhpGedView
// Copyright (C) 2002 to 2009 PGV Development Team. All rights reserved.
@@ -92,7 +92,7 @@ class WT_Controller_Descendancy extends WT_Controller_Chart {
$this->cellwidth=(strlen($this->name)*14);
}
- if ($this->root && $this->root->canDisplayName()) {
+ if ($this->root && $this->root->canShowName()) {
$this->setPageTitle(
/* I18N: %s is an individual’s name */
WT_I18N::translate('Descendants of %s', $this->root->getFullName())
@@ -199,7 +199,7 @@ class WT_Controller_Descendancy extends WT_Controller_Chart {
$spouse=$family->getSpouse($person);
if (!$spouse) {
// One parent families have no spouse
- $spouse=new WT_Person('');
+ $spouse=new WT_Individual('');
}
// print marriage info
@@ -244,7 +244,7 @@ class WT_Controller_Descendancy extends WT_Controller_Chart {
} else {
// Distinguish between no children (NCHI 0) and no recorded
// children (no CHIL records)
- if (strpos($family->getGedcomRecord(), '\n1 NCHI 0')) {
+ if (strpos($family->getGedcom(), '\n1 NCHI 0')) {
echo WT_Gedcom_Tag::getLabel('NCHI').': '.count($children);
} else {
echo WT_I18N::translate('No children');
diff --git a/library/WT/Controller/Family.php b/library/WT/Controller/Family.php
index 68151a0d35..686627562b 100644
--- a/library/WT/Controller/Family.php
+++ b/library/WT/Controller/Family.php
@@ -2,7 +2,7 @@
// Controller for the family page
//
// webtrees: Web based Family History software
-// Copyright (C) 2012 webtrees development team.
+// Copyright (C) 2013 webtrees development team.
//
// Derived from PhpGedView
// Copyright (C) 2002 to 2010 PGV Development Team. All rights reserved.
@@ -32,46 +32,14 @@ require_once WT_ROOT.'includes/functions/functions_print_facts.php';
require_once WT_ROOT.'includes/functions/functions_import.php';
class WT_Controller_Family extends WT_Controller_GedcomRecord {
- var $diff_record;
- var $record = null;
- var $user = null;
- var $display = false;
- var $famrec = '';
- var $title = '';
-
public function __construct() {
global $Dbwidth, $bwidth, $pbwidth, $pbheight, $bheight;
- $bwidth = $Dbwidth;
- $pbwidth = $bwidth + 12;
+ $bwidth = $Dbwidth;
+ $pbwidth = $bwidth + 12;
$pbheight = $bheight + 14;
- $xref = safe_GET_xref('famid');
-
- $gedrec = find_family_record($xref, WT_GED_ID);
-
- if (empty($gedrec)) {
- $gedrec = "0 @".$xref."@ FAM\n";
- }
-
- if (find_family_record($xref, WT_GED_ID) || find_updated_record($xref, WT_GED_ID)!==null) {
- $this->record = new WT_Family($gedrec);
- $this->record->ged_id=WT_GED_ID; // This record is from a file
- } else if (!$this->record) {
- parent::__construct();
- return;
- }
-
- $xref=$this->record->getXref(); // Correct upper/lower case mismatch
-
- //-- if the user can edit and there are changes then get the new changes
- if (WT_USER_CAN_EDIT) {
- $newrec = find_updated_record($xref, WT_GED_ID);
- if (!empty($newrec)) {
- $this->diff_record = new WT_Family($newrec);
- $this->diff_record->setChanged(true);
- $this->record->diffMerge($this->diff_record);
- }
- }
+ $xref = safe_GET_xref('famid');
+ $this->record = WT_Family::getInstance($xref);
parent::__construct();
}
@@ -98,7 +66,7 @@ class WT_Controller_Family extends WT_Controller_GedcomRecord {
// $tags is an array of HUSB/WIFE/CHIL
function getTimelineIndis($tags) {
- preg_match_all('/\n1 (?:'.implode('|', $tags).') @('.WT_REGEX_XREF.')@/', $this->record->getGedcomRecord(), $matches);
+ preg_match_all('/\n1 (?:'.implode('|', $tags).') @('.WT_REGEX_XREF.')@/', $this->record->getGedcom(), $matches);
foreach ($matches[1] as &$match) {
$match='pids[]='.$match;
}
@@ -111,7 +79,7 @@ class WT_Controller_Family extends WT_Controller_GedcomRecord {
function getEditMenu() {
$SHOW_GEDCOM_RECORD=get_gedcom_setting(WT_GED_ID, 'SHOW_GEDCOM_RECORD');
- if (!$this->record || $this->record->isMarkedDeleted()) {
+ if (!$this->record || $this->record->isOld()) {
return null;
}
@@ -138,21 +106,6 @@ class WT_Controller_Family extends WT_Controller_GedcomRecord {
}
}
- // edit/view raw gedcom
- if (WT_USER_IS_ADMIN || $SHOW_GEDCOM_RECORD) {
- $submenu = new WT_Menu(WT_I18N::translate('Edit raw GEDCOM record'), '#', 'menu-fam-editraw');
- $submenu->addOnclick("return edit_raw('".$this->record->getXref()."');");
- $menu->addSubmenu($submenu);
- } elseif ($SHOW_GEDCOM_RECORD) {
- $submenu = new WT_Menu(WT_I18N::translate('View GEDCOM Record'), '#', 'menu-fam-viewraw');
- if (WT_USER_CAN_EDIT) {
- $submenu->addOnclick("return show_gedcom_record('new');");
- } else {
- $submenu->addOnclick("return show_gedcom_record();");
- }
- $menu->addSubmenu($submenu);
- }
-
// delete
if (WT_USER_CAN_EDIT) {
$submenu = new WT_Menu(WT_I18N::translate('Delete'), '#', 'menu-fam-del');
@@ -202,7 +155,6 @@ class WT_Controller_Family extends WT_Controller_GedcomRecord {
foreach ($indifacts as $fact) {
print_fact($fact, $this->record);
}
- print_main_media($this->record->getXref());
} else {
echo '<tr><td class="messagebox" colspan="2">', WT_I18N::translate('No facts for this family.'), '</td></tr>';
}
diff --git a/library/WT/Controller/Familybook.php b/library/WT/Controller/Familybook.php
index e75a46b6a6..c509a10af4 100644
--- a/library/WT/Controller/Familybook.php
+++ b/library/WT/Controller/Familybook.php
@@ -2,7 +2,7 @@
// Controller for the familybook chart
//
// webtrees: Web based Family History software
-// Copyright (C) 2012 webtrees development team.
+// Copyright (C) 2013 webtrees development team.
//
// Derived from PhpGedView
// Copyright (C) 2002 to 2009 PGV Development Team. All rights reserved.
@@ -64,7 +64,7 @@ class WT_Controller_Familybook extends WT_Controller_Chart {
// Validate parameters
if (!empty($rootid)) $this->pid = $rootid;
$rootid=$this->rootid;
- $this->hourPerson = WT_Person::getInstance($this->pid);
+ $this->hourPerson = WT_Individual::getInstance($this->pid);
if (!$this->hourPerson) {
$this->hourPerson=$this->getSignificantIndividual();
$this->pid=$this->hourPerson->getXref();
@@ -75,7 +75,7 @@ class WT_Controller_Familybook extends WT_Controller_Chart {
$bheight = $cbheight;
}
$bhalfheight = $bheight / 2;
- if ($this->root && $this->root->canDisplayName()) {
+ if ($this->root && $this->root->canShowName()) {
$this->setPageTitle(
/* I18N: %s is an individual’s name */
WT_I18N::translate('Family book of %s', $this->root->getFullName())
@@ -334,7 +334,7 @@ class WT_Controller_Familybook extends WT_Controller_Chart {
*/
function max_descendency_generations($pid, $depth) {
if ($depth > $this->generations) return $depth;
- $person = WT_Person::getInstance($pid);
+ $person = WT_Individual::getInstance($pid);
if (is_null($person)) return $depth;
$maxdc = $depth;
foreach ($person->getSpouseFamilies() as $family) {
@@ -360,7 +360,7 @@ class WT_Controller_Familybook extends WT_Controller_Chart {
}
function print_family_book($person, $descent) {
global $firstrun;
- if ($descent==0 || !$person->canDisplayName()) {
+ if ($descent==0 || !$person->canShowName()) {
return;
}
$families=$person->getSpouseFamilies();
diff --git a/library/WT/Controller/Fanchart.php b/library/WT/Controller/Fanchart.php
index 2b86dab1d6..ea6edf7c12 100644
--- a/library/WT/Controller/Fanchart.php
+++ b/library/WT/Controller/Fanchart.php
@@ -2,7 +2,7 @@
// Controller for the fan chart
//
// webtrees: Web based Family History software
-// Copyright (C) 2012 webtrees development team.
+// Copyright (C) 2013 webtrees development team.
//
// Derived from PhpGedView
// Copyright (C) 2002 to 2009 PGV Development Team. All rights reserved.
@@ -46,7 +46,7 @@ class WT_Controller_Fanchart extends WT_Controller_Chart {
$this->fan_width =safe_GET_integer('fan_width', 50, 300, 100);
$this->generations=safe_GET_integer('generations', 2, 9, $default_generations);
- if ($this->root && $this->root->canDisplayName()) {
+ if ($this->root && $this->root->canShowName()) {
$this->setPageTitle(
/* I18N: http://en.wikipedia.org/wiki/Family_tree#Fan_chart - %s is an individual’s name */
WT_I18N::translate('Fan chart of %s', $this->root->getFullName())
@@ -211,7 +211,7 @@ class WT_Controller_Fanchart extends WT_Controller_Chart {
while ($sosa >= $p2) {
$pid=$treeid[$sosa];
if ($pid) {
- $person =WT_Person::getInstance($pid);
+ $person =WT_Individual::getInstance($pid);
$name =$person->getFullName();
$addname=$person->getAddName();
@@ -234,8 +234,8 @@ class WT_Controller_Fanchart extends WT_Controller_Chart {
$text .= $person->getLifeSpan();
- $text = unhtmlentities($text);
$text = strip_tags($text);
+ $text = htmlspecialchars_decode($text);
// split and center text by lines
$wmax = (int)($angle*7/$fanChart['size']*$scale);
diff --git a/library/WT/Controller/GedcomRecord.php b/library/WT/Controller/GedcomRecord.php
index 18c64bd9fa..233c7fbaac 100644
--- a/library/WT/Controller/GedcomRecord.php
+++ b/library/WT/Controller/GedcomRecord.php
@@ -29,6 +29,22 @@ class WT_Controller_GedcomRecord extends WT_Controller_Page {
public $record; // individual, source, repository, etc.
public function __construct() {
+ // Automatically fix broken links
+ if ($this->record && $this->record->canEdit()) {
+ $broken_links=0;
+ foreach ($this->record->getFacts('HUSB|WIFE|CHIL|FAMS|FAMC|SOUR|REPO|OBJE') as $fact) { // Not NOTE!
+ if (!$fact->isOld() && $fact->getTarget() === null) {
+ $this->record->updateFact($fact->getFactId(), null, false);
+ WT_FlashMessages::addMessage(/* I18N: %s are names of records, such as sources, repositories or individuals */ WT_I18N::translate('The link from “%1$s” to “%2$s” has been deleted.', $this->record->getFullName(), $fact->getValue()));
+ $broken_links = true;
+ }
+ }
+ if ($broken_links) {
+ // Reload the updated family
+ $this->record = WT_GedcomRecord::getInstance($this->record->getXref());
+ }
+ }
+
parent::__construct();
// We want robots to index this page
@@ -37,7 +53,7 @@ class WT_Controller_GedcomRecord extends WT_Controller_Page {
// Set a page title
if ($this->record) {
$this->setCanonicalUrl($this->record->getHtmlUrl());
- if ($this->record->canDisplayName()) {
+ if ($this->record->canShowName()) {
// e.g. "John Doe" or "1881 Census of Wales"
$this->setPageTitle($this->record->getFullName());
} else {
diff --git a/library/WT/Controller/Hourglass.php b/library/WT/Controller/Hourglass.php
index 7dee4869e3..01285b296b 100644
--- a/library/WT/Controller/Hourglass.php
+++ b/library/WT/Controller/Hourglass.php
@@ -2,7 +2,7 @@
// Controller for the hourglass chart
//
// webtrees: Web based Family History software
-// Copyright (C) 2012 webtrees development team.
+// Copyright (C) 2013 webtrees development team.
//
// Derived from PhpGedView
// Copyright (C) 2002 to 2009 PGV Development Team. All rights reserved.
@@ -90,7 +90,7 @@ class WT_Controller_Hourglass extends WT_Controller_Chart {
$bhalfheight = (int)($bheight / 2);
// Validate parameters
- $this->hourPerson = WT_Person::getInstance($this->pid);
+ $this->hourPerson = WT_Individual::getInstance($this->pid);
if (!$this->hourPerson) {
$this->hourPerson=$this->getSignificantIndividual();
$this->pid=$this->hourPerson->getXref();
@@ -347,7 +347,7 @@ class WT_Controller_Hourglass extends WT_Controller_Chart {
// For the root person, print a down arrow that allows changing the root of tree
if ($showNav && $count==1) {
// NOTE: If statement OK
- if ($person->canDisplayName()) {
+ if ($person->canShowName()) {
// -- print left arrow for decendants so that we can move down the tree
$famids = $person->getSpouseFamilies();
//-- make sure there is more than 1 child in the family with parents
@@ -435,7 +435,7 @@ class WT_Controller_Hourglass extends WT_Controller_Chart {
*/
function max_descendency_generations($pid, $depth) {
if ($depth > $this->generations) return $depth;
- $person = WT_Person::getInstance($pid);
+ $person = WT_Individual::getInstance($pid);
if (is_null($person)) return $depth;
$maxdc = $depth;
foreach ($person->getSpouseFamilies() as $family) {
diff --git a/library/WT/Controller/Individual.php b/library/WT/Controller/Individual.php
index 26cf33b4ec..c09304fa32 100644
--- a/library/WT/Controller/Individual.php
+++ b/library/WT/Controller/Individual.php
@@ -32,58 +32,29 @@ require_once WT_ROOT.'includes/functions/functions_print_facts.php';
require_once WT_ROOT.'includes/functions/functions_import.php';
class WT_Controller_Individual extends WT_Controller_GedcomRecord {
- var $name_count = 0;
- var $total_names = 0;
- var $SEX_COUNT = 0;
- var $Fam_Navigator = 'YES';
- var $NAME_LINENUM = null;
- var $SEX_LINENUM = null;
- var $globalfacts = null;
+ public $name_count = 0;
+ public $total_names = 0;
+
public $tabs;
function __construct() {
- global $USE_RIN, $MAX_ALIVE_AGE, $SEARCH_SPIDER;
- global $DEFAULT_PIN_STATE, $DEFAULT_SB_CLOSED_STATE;
- global $Fam_Navigator;
-
- $xref = safe_GET_xref('pid');
-
- $gedrec = find_person_record($xref, WT_GED_ID);
-
- if ($USE_RIN && $gedrec==false) {
- $xref = find_rin_id($xref);
- $gedrec = find_person_record($xref, WT_GED_ID);
- }
- if (empty($gedrec)) {
- $gedrec = "0 @".$xref."@ INDI\n";
- }
+ global $USE_RIN;
- if (find_person_record($xref, WT_GED_ID) || find_updated_record($xref, WT_GED_ID)!==null) {
- $this->record = new WT_Person($gedrec);
- $this->record->ged_id=WT_GED_ID; // This record is from a file
- } else if (!$this->record) {
- parent::__construct();
- return;
- }
+ $xref = safe_GET_xref('pid');
+ $this->record = WT_Individual::getInstance($xref);
- //-- if the user can edit and there are changes then get the new changes
- if (WT_USER_CAN_EDIT || WT_USER_CAN_ACCEPT) {
- $newrec = find_updated_record($xref, WT_GED_ID);
- if (!empty($newrec)) {
- $diff_record = new WT_Person($newrec);
- $diff_record->setChanged(true);
- $this->record->diffMerge($diff_record);
- }
+ if (!$this->record && $USE_RIN) {
+ $rin = find_rin_id($xref);
+ $this->record = WT_Individual::getInstance($rin);
}
- $this->tabs=WT_Module::getActiveTabs();
-
- // Our parent needs $this->record
parent::__construct();
+ $this->tabs = WT_Module::getActiveTabs();
+
// If we can display the details, add them to the page header
- if ($this->record && $this->record->canDisplayDetails()) {
- $this->setPageTitle($this->record->getFullName().' '.$this->record->getLifespan());
+ if ($this->record && $this->record->canShow()) {
+ $this->setPageTitle($this->record->getFullName() . ' ' . $this->record->getLifespan());
}
}
@@ -147,29 +118,33 @@ class WT_Controller_Individual extends WT_Controller_GedcomRecord {
* @see individual.php
* @param Event $event the event object
*/
- function print_name_record(WT_Event $event) {
+ function print_name_record(WT_Fact $event) {
if (!$event->canShow()) {
return false;
}
- $factrec = $event->getGedComRecord();
- $linenum = $event->getLineNumber();
+ $factrec = $event->getGedcom();
// Create a dummy record, so we can extract the formatted NAME value from the event.
- $dummy=new WT_Person('0 @'.$event->getParentObject()->getXref()."@ INDI\n1 DEAT Y\n".$factrec);
+ $dummy=new WT_Individual(
+ 'xref',
+ "0 @xref@ INDI\n1 DEAT Y\n".$factrec,
+ null,
+ WT_GED_ID
+ );
$all_names=$dummy->getAllNames();
$primary_name=$all_names[0];
$this->name_count++;
if ($this->name_count >1) { echo '<h3 class="name_two">',$dummy->getFullName(), '</h3>'; } //Other names accordion element
- echo '<div class="indi_name_details"';
- if ($event->getIsOld()) {
- echo " class=\"namered\"";
+ echo '<div class="indi_name_details';
+ if ($event->isOld()) {
+ echo ' old';
}
- if ($event->getIsNew()) {
- echo " class=\"nameblue\"";
+ if ($event->isNew()) {
+ echo ' new';
}
- echo ">";
+ echo '">';
echo '<div class="name1">';
echo '<dl><dt class="label">', WT_I18N::translate('Name'), '</dt>';
@@ -184,9 +159,9 @@ class WT_Controller_Individual extends WT_Controller_GedcomRecord {
}
}
}
- if ($this->record->canEdit() && !$event->getIsOld()) {
- echo "<div class=\"deletelink\"><a class=\"font9 deleteicon\" href=\"#\" onclick=\"return delete_fact('".$this->record->getXref()."', ".$linenum.", '', '".WT_I18N::translate('Are you sure you want to delete this fact?')."');\" title=\"".WT_I18N::translate('Delete name')."\"><span class=\"link_text\">".WT_I18N::translate('Delete name')."</span></a></div>";
- echo "<div class=\"editlink\"><a href=\"#\" class=\"font9 editicon\" onclick=\"edit_name('".$this->record->getXref()."', ".$linenum."); return false;\" title=\"".WT_I18N::translate('Edit name')."\"><span class=\"link_text\">".WT_I18N::translate('Edit name')."</span></a></div>";
+ if ($this->record->canEdit() && !$event->isOld()) {
+ echo "<div class=\"deletelink\"><a class=\"font9 deleteicon\" href=\"#\" onclick=\"return delete_fact('".WT_I18N::translate('Are you sure you want to delete this fact?')."', '".$this->record->getXref()."', '".$event->getFactId()."');\" title=\"".WT_I18N::translate('Delete name')."\"><span class=\"link_text\">".WT_I18N::translate('Delete name')."</span></a></div>";
+ echo "<div class=\"editlink\"><a href=\"#\" class=\"font9 editicon\" onclick=\"edit_name('".$this->record->getXref()."', '".$event->getFactId()."'); return false;\" title=\"".WT_I18N::translate('Edit name')."\"><span class=\"link_text\">".WT_I18N::translate('Edit name')."</span></a></div>";
}
echo '</dd>';
echo '</dl>';
@@ -243,50 +218,45 @@ class WT_Controller_Individual extends WT_Controller_GedcomRecord {
* @see individual.php
* @param Event $event the Event object
*/
- function print_sex_record(WT_Event $event) {
- global $sex;
-
- if (!$event->canShow()) return false;
- $factrec = $event->getGedComRecord();
- $sex = $event->getDetail();
+ function print_sex_record(WT_Fact $event) {
+ $sex = $event->getValue();
if (empty($sex)) $sex = 'U';
- echo '<span id="sex"';
- echo ' class="';
- if ($event->getIsOld()) {
- echo 'namered ';
- }
- if ($event->getIsNew()) {
- echo 'nameblue ';
- }
- switch ($sex) {
- case 'M':
- echo 'male_gender"';
- if ($this->record->canEdit() && !$event->getIsOld()) {
- echo ' title="', WT_I18N::translate('Male'), ' - ', WT_I18N::translate('Edit'), '"';
- echo ' onclick="edit_record(\''.$this->record->getXref().'\', '.$event->getLineNumber().'); return false;">&nbsp;';
- } else {
- echo ' title="', WT_I18N::translate('Male'), '">&nbsp;';
- }
- break;
- case 'F':
- echo 'female_gender"';
- if ($this->record->canEdit() && !$event->getIsOld()) {
- echo ' title="', WT_I18N::translate('Female'), ' - ', WT_I18N::translate('Edit'), '"';
- echo ' onclick="edit_record(\''.$this->record->getXref().'\', '.$event->getLineNumber().'); return false;">&nbsp;';
- } else {
- echo ' title="', WT_I18N::translate('Female'), '">&nbsp;';
- }
- break;
- case 'U':
- echo 'unknown_gender"';
- if ($this->record->canEdit() && !$event->getIsOld()) {
- echo ' title="', WT_I18N::translate_c('unknown gender', 'Unknown'), ' - ', WT_I18N::translate('Edit'), '"';
- echo ' onclick="edit_record(\''.$this->record->getXref().'\', '.$event->getLineNumber().'); return false;">&nbsp;';
- } else {
- echo ' title="', WT_I18N::translate_c('unknown gender', 'Unknown'), '">&nbsp;';
- }
- break;
- }
+ echo '<span id="sex" class="';
+ if ($event->isOld()) {
+ echo 'old';
+ }
+ if ($event->isNew()) {
+ echo 'new';
+ }
+ switch ($sex) {
+ case 'M':
+ echo ' male_gender"';
+ if ($event->canEdit()) {
+ echo ' title="', WT_I18N::translate('Male'), ' - ', WT_I18N::translate('Edit'), '"';
+ echo ' onclick="edit_record(\''.$this->record->getXref().'\', \''.$event->getFactId().'\'); return false;">';
+ } else {
+ echo ' title="', WT_I18N::translate('Male'), '">';
+ }
+ break;
+ case 'F':
+ echo ' female_gender"';
+ if ($event->canEdit()) {
+ echo ' title="', WT_I18N::translate('Female'), ' - ', WT_I18N::translate('Edit'), '"';
+ echo ' onclick="edit_record(\''.$this->record->getXref().'\', \''.$event->getFactId().'\'); return false;">';
+ } else {
+ echo ' title="', WT_I18N::translate('Female'), '">';
+ }
+ break;
+ case 'U':
+ echo ' unknown_gender"';
+ if ($event->canEdit()) {
+ echo ' title="', WT_I18N::translate_c('unknown gender', 'Unknown'), ' - ', WT_I18N::translate('Edit'), '"';
+ echo ' onclick="edit_record(\''.$this->record->getXref().'\', \''.$event->getFactId().'\'); return false;">';
+ } else {
+ echo ' title="', WT_I18N::translate_c('unknown gender', 'Unknown'), '">';
+ }
+ break;
+ }
echo '</span>';
}
/**
@@ -295,39 +265,41 @@ class WT_Controller_Individual extends WT_Controller_GedcomRecord {
function getEditMenu() {
$SHOW_GEDCOM_RECORD=get_gedcom_setting(WT_GED_ID, 'SHOW_GEDCOM_RECORD');
- if (!$this->record || $this->record->isMarkedDeleted()) {
+ if (!$this->record || $this->record->isOld()) {
return null;
}
// edit menu
$menu = new WT_Menu(WT_I18N::translate('Edit'), '#', 'menu-indi');
$menu->addLabel($menu->label, 'down');
- $this->getGlobalFacts(); // sets NAME_LINENUM and SEX_LINENUM. individual.php doesn't do it early enough for us....
-
// What behaviour shall we give the main menu? If we leave it blank, the framework
// will copy the first submenu - which may be edit-raw or delete.
// As a temporary solution, make it edit the name
- if (WT_USER_CAN_EDIT && $this->NAME_LINENUM) {
- $menu->addOnclick("return edit_name('".$this->record->getXref()."', ".$this->NAME_LINENUM.");");
- } else {
- $menu->addOnclick("return false;");
- }
-
+ $menu->addOnclick("return false;");
if (WT_USER_CAN_EDIT) {
- //--make sure the totals are correct
+ foreach ($this->record->getFacts() as $fact) {
+ if ($fact->getTag()=='NAME' && $fact->canShow() && $fact->canEdit())
+ $menu->addOnclick("return edit_name('".$this->record->getXref() . "', '" . $fact->getFactId() . "');");
+ break;
+ }
+
$submenu = new WT_Menu(WT_I18N::translate('Add new Name'), '#', 'menu-indi-addname');
$submenu->addOnclick("return add_name('".$this->record->getXref()."');");
$menu->addSubmenu($submenu);
- if ($this->SEX_COUNT<2) {
- $submenu = new WT_Menu(WT_I18N::translate('Edit gender'), '#', 'menu-indi-editsex');
- if ($this->SEX_LINENUM=="new") {
- $submenu->addOnclick("return add_new_record('".$this->record->getXref()."', 'SEX');");
- } else {
- $submenu->addOnclick("return edit_record('".$this->record->getXref()."', ".$this->SEX_LINENUM.");");
+ $has_sex_record = false;
+ $submenu = new WT_Menu(WT_I18N::translate('Edit gender'), '#', 'menu-indi-editsex');
+ foreach ($this->record->getFacts() as $fact) {
+ if ($fact->getTag()=='SEX' && $fact->canShow() && $fact->canEdit()) {
+ $submenu->addOnclick("return edit_record('" . $this->record->getXref() . "', '" . $fact->getFactId() . "');");
+ $has_sex_record = true;
+ break;
}
- $menu->addSubmenu($submenu);
}
+ if (!$has_sex_record) {
+ $submenu->addOnclick("return add_new_record('" . $this->record->getXref() . "', 'SEX');");
+ }
+ $menu->addSubmenu($submenu);
if (count($this->record->getSpouseFamilies())>1) {
$submenu = new WT_Menu(WT_I18N::translate('Re-order families'), '#', 'menu-indi-orderfam');
@@ -336,21 +308,6 @@ class WT_Controller_Individual extends WT_Controller_GedcomRecord {
}
}
- // edit/view raw gedcom
- if (WT_USER_IS_ADMIN || $SHOW_GEDCOM_RECORD) {
- $submenu = new WT_Menu(WT_I18N::translate('Edit raw GEDCOM record'), '#', 'menu-indi-editraw');
- $submenu->addOnclick("return edit_raw('".$this->record->getXref()."');");
- $menu->addSubmenu($submenu);
- } elseif ($SHOW_GEDCOM_RECORD) {
- $submenu = new WT_Menu(WT_I18N::translate('View GEDCOM Record'), '#', 'menu-indi-viewraw');
- if (WT_USER_CAN_EDIT) {
- $submenu->addOnclick("return show_gedcom_record('new');");
- } else {
- $submenu->addOnclick("return show_gedcom_record();");
- }
- $menu->addSubmenu($submenu);
- }
-
// delete
if (WT_USER_CAN_EDIT) {
$submenu = new WT_Menu(WT_I18N::translate('Delete'), '#', 'menu-indi-del');
@@ -372,48 +329,7 @@ class WT_Controller_Individual extends WT_Controller_GedcomRecord {
return $menu;
}
- /**
- * get global facts
- * global facts are NAME and SEX
- * @return array return the array of global facts
- */
- function getGlobalFacts() {
- if ($this->globalfacts==null) {
- $this->globalfacts = $this->record->getGlobalFacts();
- foreach ($this->globalfacts as $key => $value) {
- $fact = $value->getTag();
- if ($fact=="SEX") {
- $this->SEX_COUNT++;
- $this->SEX_LINENUM = $value->getLineNumber();
- }
- if ($fact=="NAME") {
- $this->total_names++;
- if ($this->NAME_LINENUM==null && !$value->getIsOld()) {
- // This is the "primary" name and is edited from the menu
- // Subsequent names get their own edit links
- $this->NAME_LINENUM = $value->getLineNumber();
- }
- }
- }
- }
- return $this->globalfacts;
- }
- /**
- * get the individual facts shown on tab 1
- * @return array
- */
- function getIndiFacts() {
- $indifacts = $this->record->getIndiFacts();
- sort_facts($indifacts);
- return $indifacts;
- }
- /**
- * get the other facts shown on tab 2
- * @return array
- */
- function getOtherFacts() {
- $otherfacts = $this->record->getOtherFacts();
- return $otherfacts;
+ function add_asso_facts() {
}
/**
@@ -514,22 +430,10 @@ class WT_Controller_Individual extends WT_Controller_GedcomRecord {
$newwife = null;
$newchildren = array();
$delchildren = array();
- $children = array();
- $husb = null;
- $wife = null;
- if (!$family->getChanged()) {
- $husb = $family->getHusband();
- $wife = $family->getWife();
- $children = $family->getChildren();
- }
- //-- step families : set the label for the common parent
- if ($type=="step-parents") {
- $fams = $this->record->getChildFamilies();
- foreach ($fams as $key=>$fam) {
- if ($fam->hasParent($husb)) $labels["father"] = get_relationship_name_from_path('fat', null, null);
- if ($fam->hasParent($wife)) $labels["mother"] = get_relationship_name_from_path('mot', null, null);
- }
- }
+ $husb = $family->getHusband();
+ $wife = $family->getWife();
+ $children = $family->getChildren();
+
//-- set the label for the husband
if (!is_null($husb)) {
$label = $labels["parent"];
@@ -560,80 +464,6 @@ class WT_Controller_Individual extends WT_Controller_GedcomRecord {
}
$wife->setLabel($label);
}
- if (WT_USER_CAN_EDIT || WT_USER_CAN_ACCEPT) {
- $newfamily = $family->getUpdatedFamily();
- if (!is_null($newfamily)) {
- $newhusb = $newfamily->getHusband();
- //-- check if the husband in the family has changed
- if (!is_null($newhusb) && !$newhusb->equals($husb)) {
- $label = $labels["parent"];
- $sex = $newhusb->getSex();
- if ($sex=="F") {
- $label = $labels["mother"];
- }
- if ($sex=="M") {
- $label = $labels["father"];
- }
- if ($newhusb->getXref()==$this->record->getXref()) {
- $label = '<i class="icon-selected"></i>';
- }
- $newhusb->setLabel($label);
- }
- else $newhusb = null;
- $newwife = $newfamily->getWife();
- //-- check if the wife in the family has changed
- if (!is_null($newwife) && !$newwife->equals($wife)) {
- $label = $labels["parent"];
- $sex = $newwife->getSex();
- if ($sex=="F") {
- $label = $labels["mother"];
- }
- if ($sex=="M") {
- $label = $labels["father"];
- }
- if ($newwife->getXref()==$this->record->getXref()) {
- $label = '<i class="icon-selected"></i>';
- }
- $newwife->setLabel($label);
- }
- else $newwife = null;
- //-- check for any new children
- $merged_children = array();
- $new_children = $newfamily->getChildren();
- $num = count($children);
- for ($i=0; $i<$num; $i++) {
- $child = $children[$i];
- if (!is_null($child)) {
- $found = false;
- foreach ($new_children as $key=>$newchild) {
- if (!is_null($newchild)) {
- if ($child->equals($newchild)) {
- $found = true;
- break;
- }
- }
- }
- if (!$found) $delchildren[] = $child;
- else $merged_children[] = $child;
- }
- }
- foreach ($new_children as $key=>$newchild) {
- if (!is_null($newchild)) {
- $found = false;
- foreach ($children as $key1=>$child) {
- if (!is_null($child)) {
- if ($child->equals($newchild)) {
- $found = true;
- break;
- }
- }
- }
- if (!$found) $newchildren[] = $newchild;
- }
- }
- $children = $merged_children;
- }
- }
//-- set the labels for the children
$num = count($children);
for ($i=0; $i<$num; $i++) {
@@ -650,7 +480,7 @@ class WT_Controller_Individual extends WT_Controller_GedcomRecord {
$label = '<i class="icon-selected"></i>';
}
if ($include_pedi==true) {
- $famcrec = get_sub_record(1, "1 FAMC @".$family->getXref()."@", $children[$i]->getGedcomRecord());
+ $famcrec = get_sub_record(1, "1 FAMC @".$family->getXref()."@", $children[$i]->getGedcom());
$pedi = get_gedcom_value("PEDI", 2, $famcrec);
if ($pedi) {
$label.='<br>('.WT_Gedcom_Code_Pedi::getValue($pedi, $children[$i]).')';
diff --git a/library/WT/Controller/Lifespan.php b/library/WT/Controller/Lifespan.php
index 60c6664289..4c4f325d30 100644
--- a/library/WT/Controller/Lifespan.php
+++ b/library/WT/Controller/Lifespan.php
@@ -122,7 +122,7 @@ class WT_Controller_Lifespan extends WT_Controller_Page {
}
}
} elseif ($newpid) {
- $person=WT_Person::getInstance($newpid);
+ $person=WT_Individual::getInstance($newpid);
$this->addFamily($person, $addfam);
} elseif (!$this->pids) {
$this->addFamily($this->getSignificantIndividual(), false);
@@ -138,13 +138,13 @@ class WT_Controller_Lifespan extends WT_Controller_Page {
foreach ($this->pids as $key => $value) {
if ($value != $remove) {
$this->pids[$key] = $value;
- $person = WT_Person::getInstance($value);
+ $person = WT_Individual::getInstance($value);
// list of linked records includes families as well as individuals.
if ($person) {
$bdate = $person->getEstimatedBirthDate();
$ddate = $person->getEstimatedDeathDate();
//--Checks to see if the details of that person can be viewed
- if ($bdate->isOK() && $person->canDisplayDetails()) {
+ if ($bdate->isOK() && $person->canShow()) {
$this->people[] = $person;
}
}
@@ -169,7 +169,7 @@ class WT_Controller_Lifespan extends WT_Controller_Page {
$bdate = $person->getEstimatedBirthDate();
$ddate = $person->getEstimatedDeathDate();
//--Checks to see if the details of that person can be viewed
- if ($bdate->isOK() && $person->canDisplayDetails()) {
+ if ($bdate->isOK() && $person->canShow()) {
$this->people[] = $person;
}
}
@@ -424,7 +424,7 @@ class WT_Controller_Lifespan extends WT_Controller_Page {
$evntwdth = $eventwidth."%";
//-- if the fact is a generic EVENt then get the qualifying TYPE
if ($fact=="EVEN") {
- $fact = $val->getType();
+ $fact = $val->getAttribute('TYPE');
}
$place = $val->getPlace();
$trans = WT_Gedcom_Tag::getLabel($fact);
@@ -532,18 +532,18 @@ class WT_Controller_Lifespan extends WT_Controller_Page {
$endjd =WT_Date_Gregorian::YMDtoJD($endyear+1, 1, 1)-1;
$sql=
- "SELECT DISTINCT 'INDI' AS type, i_id AS xref, i_file AS ged_id, i_gedcom AS gedrec".
+ "SELECT DISTINCT i_id AS xref, i_file AS gedcom_id, i_gedcom AS gedcom".
" FROM `##individuals`".
" JOIN `##dates` ON i_id=d_gid AND i_file=d_file".
" WHERE i_file=? AND d_julianday1 BETWEEN ? AND ?";
$rows=WT_DB::prepare($sql)
->execute(array(WT_GED_ID, $startjd, $endjd))
- ->fetchAll(PDO::FETCH_ASSOC);
+ ->fetchAll();
$list=array();
foreach ($rows as $row) {
- $list[]=WT_Person::getInstance($row);
+ $list[]=WT_Individual::getInstance($row->xref, $row->gedcom_id, $row->gedcom);
}
return $list;
}
diff --git a/library/WT/Controller/Media.php b/library/WT/Controller/Media.php
index 562bf8aabe..c9fbf39547 100644
--- a/library/WT/Controller/Media.php
+++ b/library/WT/Controller/Media.php
@@ -2,7 +2,7 @@
// Controller for the media page
//
// webtrees: Web based Family History software
-// Copyright (C) 2012 webtrees development team.
+// Copyright (C) 2013 webtrees development team.
//
// Derived from PhpGedView
// Copyright (C) 2002 to 2009 PGV Development Team. All rights reserved.
@@ -34,35 +34,8 @@ require_once WT_ROOT.'includes/functions/functions_import.php';
class WT_Controller_Media extends WT_Controller_GedcomRecord {
public function __construct() {
- $xref = safe_GET_xref('mid');
-
- $gedrec=find_media_record($xref, WT_GED_ID);
- if (WT_USER_CAN_EDIT) {
- $newrec=find_updated_record($xref, WT_GED_ID);
- } else {
- $newrec=null;
- }
-
- if ($gedrec===null) {
- if ($newrec===null) {
- // Nothing to see here.
- parent::__construct();
- return;
- } else {
- // Create a dummy record from the first line of the new record.
- // We need it for diffMerge(), getXref(), etc.
- list($gedrec)=explode("\n", $newrec);
- }
- }
-
- $this->record = new WT_Media($gedrec);
-
- // If there are pending changes, merge them in.
- if ($newrec!==null) {
- $diff_record=new WT_Media($newrec);
- $diff_record->setChanged(true);
- $this->record->diffMerge($diff_record);
- }
+ $xref = safe_GET_xref('mid');
+ $this->record = WT_Media::getInstance($xref);
parent::__construct();
}
@@ -73,7 +46,7 @@ class WT_Controller_Media extends WT_Controller_GedcomRecord {
function getEditMenu() {
$SHOW_GEDCOM_RECORD=get_gedcom_setting(WT_GED_ID, 'SHOW_GEDCOM_RECORD');
- if (!$this->record || $this->record->isMarkedDeleted()) {
+ if (!$this->record || $this->record->isOld()) {
return null;
}
@@ -107,21 +80,6 @@ class WT_Controller_Media extends WT_Controller_GedcomRecord {
$menu->addSubmenu($submenu);
}
- // edit/view raw gedcom
- if (WT_USER_IS_ADMIN || $SHOW_GEDCOM_RECORD) {
- $submenu = new WT_Menu(WT_I18N::translate('Edit raw GEDCOM record'), '#', 'menu-obje-editraw');
- $submenu->addOnclick("return edit_raw('".$this->record->getXref()."');");
- $menu->addSubmenu($submenu);
- } elseif ($SHOW_GEDCOM_RECORD) {
- $submenu = new WT_Menu(WT_I18N::translate('View GEDCOM Record'), '#', 'menu-obje-viewraw');
- if (WT_USER_CAN_EDIT || WT_USER_CAN_ACCEPT) {
- $submenu->addOnclick("return show_gedcom_record('new');");
- } else {
- $submenu->addOnclick("return show_gedcom_record();");
- }
- $menu->addSubmenu($submenu);
- }
-
// delete
if (WT_USER_CAN_EDIT) {
$submenu = new WT_Menu(WT_I18N::translate('Delete'), '#', 'menu-obje-del');
@@ -153,17 +111,17 @@ class WT_Controller_Media extends WT_Controller_GedcomRecord {
* @return array
*/
function getFacts($includeFileName=true) {
- $facts = $this->record->getFacts(array());
+ $facts = $this->record->getFacts();
// Add some dummy facts to show additional information
if ($this->record->fileExists()) {
// get height and width of image, when available
$imgsize = $this->record->getImageAttributes();
if (!empty($imgsize['WxH'])) {
- $facts[] = new WT_Event('1 __IMAGE_SIZE__ '.$imgsize['WxH'], $this->record, 0);
+ $facts[] = new WT_Fact('1 __IMAGE_SIZE__ '.$imgsize['WxH'], $this->record, 0);
}
//Prints the file size
- $facts[] = new WT_Event('1 __FILE_SIZE__ '.$this->record->getFilesize(), $this->record, 0);
+ $facts[] = new WT_Fact('1 __FILE_SIZE__ '.$this->record->getFilesize(), $this->record, 0);
}
sort_facts($facts);
diff --git a/library/WT/Controller/Note.php b/library/WT/Controller/Note.php
index 01fad484c8..003fd45acd 100644
--- a/library/WT/Controller/Note.php
+++ b/library/WT/Controller/Note.php
@@ -2,7 +2,7 @@
// Controller for the shared note page
//
// webtrees: Web based Family History software
-// Copyright (C) 2012 webtrees development team.
+// Copyright (C) 2013 webtrees development team.
//
// Derived from PhpGedView
// Copyright (C) 2009 PGV Development Team. All rights reserved.
@@ -33,35 +33,8 @@ require_once WT_ROOT.'includes/functions/functions_import.php';
class WT_Controller_Note extends WT_Controller_GedcomRecord {
public function __construct() {
- $xref=safe_GET_xref('nid');
-
- $gedrec=find_other_record($xref, WT_GED_ID);
- if (WT_USER_CAN_EDIT) {
- $newrec=find_updated_record($xref, WT_GED_ID);
- } else {
- $newrec=null;
- }
-
- if ($gedrec===null) {
- if ($newrec===null) {
- // Nothing to see here.
- parent::__construct();
- return;
- } else {
- // Create a dummy record from the first line of the new record.
- // We need it for diffMerge(), getXref(), etc.
- list($gedrec)=explode("\n", $newrec);
- }
- }
-
- $this->record = new WT_Note($gedrec);
-
- // If there are pending changes, merge them in.
- if ($newrec!==null) {
- $diff_record=new WT_Note($newrec);
- $diff_record->setChanged(true);
- $this->record->diffMerge($diff_record);
- }
+ $xref = safe_GET_xref('nid');
+ $this->record = WT_Note::getInstance($xref);
parent::__construct();
}
@@ -72,7 +45,7 @@ class WT_Controller_Note extends WT_Controller_GedcomRecord {
function getEditMenu() {
$SHOW_GEDCOM_RECORD=get_gedcom_setting(WT_GED_ID, 'SHOW_GEDCOM_RECORD');
- if (!$this->record || $this->record->isMarkedDeleted()) {
+ if (!$this->record || $this->record->isOld()) {
return null;
}
@@ -85,21 +58,6 @@ class WT_Controller_Note extends WT_Controller_GedcomRecord {
$menu->addSubmenu($submenu);
}
- // edit/view raw gedcom
- if (WT_USER_IS_ADMIN || $SHOW_GEDCOM_RECORD) {
- $submenu = new WT_Menu(WT_I18N::translate('Edit raw GEDCOM record'), '#', 'menu-note-editraw');
- $submenu->addOnclick("return edit_raw('".$this->record->getXref()."');");
- $menu->addSubmenu($submenu);
- } elseif ($SHOW_GEDCOM_RECORD) {
- $submenu = new WT_Menu(WT_I18N::translate('View GEDCOM Record'), '#', 'menu-note-viewraw');
- if (WT_USER_CAN_EDIT) {
- $submenu->addOnclick("return show_gedcom_record('new');");
- } else {
- $submenu->addOnclick("return show_gedcom_record();");
- }
- $menu->addSubmenu($submenu);
- }
-
// delete
if (WT_USER_CAN_EDIT) {
$submenu = new WT_Menu(WT_I18N::translate('Delete'), '#', 'menu-note-del');
diff --git a/library/WT/Controller/Page.php b/library/WT/Controller/Page.php
index 55a6b55cdc..d2fe6031db 100644
--- a/library/WT/Controller/Page.php
+++ b/library/WT/Controller/Page.php
@@ -163,7 +163,6 @@ class WT_Controller_Page extends WT_Controller_Base {
var browserType = "'.$BROWSERTYPE.'";
var WT_SCRIPT_NAME = "'.WT_SCRIPT_NAME.'";
var WT_LOCALE = "'.WT_LOCALE.'";
- var accesstime = '.WT_TIMESTAMP.';
', self::JS_PRIORITY_HIGH);
// Temporary fix for access to main menu hover elements on android/blackberry touch devices
@@ -220,16 +219,16 @@ class WT_Controller_Page extends WT_Controller_Base {
static $individual; // Only query the DB once.
if (!$individual && WT_USER_ROOT_ID) {
- $individual=WT_Person::getInstance(WT_USER_ROOT_ID);
+ $individual=WT_Individual::getInstance(WT_USER_ROOT_ID);
}
if (!$individual && WT_USER_GEDCOM_ID) {
- $individual=WT_Person::getInstance(WT_USER_GEDCOM_ID);
+ $individual=WT_Individual::getInstance(WT_USER_GEDCOM_ID);
}
if (!$individual) {
- $individual=WT_Person::getInstance(get_gedcom_setting(WT_GED_ID, 'PEDIGREE_ROOT_ID'));
+ $individual=WT_Individual::getInstance(get_gedcom_setting(WT_GED_ID, 'PEDIGREE_ROOT_ID'));
}
if (!$individual) {
- $individual=WT_Person::getInstance(
+ $individual=WT_Individual::getInstance(
WT_DB::prepare(
"SELECT MIN(i_id) FROM `##individuals` WHERE i_file=?"
)->execute(array(WT_GED_ID))->fetchOne()
@@ -237,7 +236,7 @@ class WT_Controller_Page extends WT_Controller_Base {
}
if (!$individual) {
// always return a record
- $individual=new WT_Person('0 @I@ INDI');
+ $individual=new WT_Individual('I', '0 @I@ INDI', null, WT_GED_ID);
}
return $individual;
}
@@ -252,7 +251,7 @@ class WT_Controller_Page extends WT_Controller_Base {
}
}
// always return a record
- return new WT_Family('0 @F@ FAM');
+ return new WT_Family('F', '0 @F@ FAM', null, WT_GED_ID);
}
public function getSignificantSurname() {
return '';
diff --git a/library/WT/Controller/Pedigree.php b/library/WT/Controller/Pedigree.php
index 65bb3174f0..5133aea959 100644
--- a/library/WT/Controller/Pedigree.php
+++ b/library/WT/Controller/Pedigree.php
@@ -2,7 +2,7 @@
// Controller for the pedigree chart
//
// webtrees: Web based Family History software
-// Copyright (C) 2012 webtrees development team.
+// Copyright (C) 2013 webtrees development team.
//
// Derived from PhpGedView
// Copyright (C) 2002 to 2009 PGV Development Team. All rights reserved.
@@ -85,7 +85,7 @@ class WT_Controller_Pedigree extends WT_Controller_Chart {
$show_full = $this->show_full;
$talloffset = $this->talloffset;
- if ($this->root && $this->root->canDisplayName()) {
+ if ($this->root && $this->root->canShowName()) {
$this->setPageTitle(
/* I18N: %s is an individual’s name */
WT_I18N::translate('Pedigree tree of %s', $this->root->getFullName())
diff --git a/library/WT/Controller/Repository.php b/library/WT/Controller/Repository.php
index 7af4c8c139..2c409a6110 100644
--- a/library/WT/Controller/Repository.php
+++ b/library/WT/Controller/Repository.php
@@ -2,7 +2,7 @@
// Controller for the repository page
//
// webtrees: Web based Family History software
-// Copyright (C) 2012 webtrees development team.
+// Copyright (C) 2013 webtrees development team.
//
// Derived from PhpGedView
// Copyright (C) 2002 to 2010 PGV Development Team. All rights reserved.
@@ -33,35 +33,8 @@ require_once WT_ROOT.'includes/functions/functions_import.php';
class WT_Controller_Repository extends WT_Controller_GedcomRecord {
public function __construct() {
- $xref = safe_GET_xref('rid');
-
- $gedrec=find_other_record($xref, WT_GED_ID);
- if (WT_USER_CAN_EDIT) {
- $newrec=find_updated_record($xref, WT_GED_ID);
- } else {
- $newrec=null;
- }
-
- if ($gedrec===null) {
- if ($newrec===null) {
- // Nothing to see here.
- parent::__construct();
- return;
- } else {
- // Create a dummy record from the first line of the new record.
- // We need it for diffMerge(), getXref(), etc.
- list($gedrec)=explode("\n", $newrec);
- }
- }
-
- $this->record = new WT_Repository($gedrec);
-
- // If there are pending changes, merge them in.
- if ($newrec!==null) {
- $diff_record=new WT_Repository($newrec);
- $diff_record->setChanged(true);
- $this->record->diffMerge($diff_record);
- }
+ $xref = safe_GET_xref('rid');
+ $this->record = WT_Repository::getInstance($xref);
parent::__construct();
}
@@ -72,7 +45,7 @@ class WT_Controller_Repository extends WT_Controller_GedcomRecord {
function getEditMenu() {
$SHOW_GEDCOM_RECORD=get_gedcom_setting(WT_GED_ID, 'SHOW_GEDCOM_RECORD');
- if (!$this->record || $this->record->isMarkedDeleted()) {
+ if (!$this->record || $this->record->isOld()) {
return null;
}
@@ -85,21 +58,6 @@ class WT_Controller_Repository extends WT_Controller_GedcomRecord {
$menu->addSubmenu($submenu);
}
- // edit/view raw gedcom
- if (WT_USER_IS_ADMIN || $SHOW_GEDCOM_RECORD) {
- $submenu = new WT_Menu(WT_I18N::translate('Edit raw GEDCOM record'), '#', 'menu-repo-editraw');
- $submenu->addOnclick("return edit_raw('".$this->record->getXref()."');");
- $menu->addSubmenu($submenu);
- } elseif ($SHOW_GEDCOM_RECORD) {
- $submenu = new WT_Menu(WT_I18N::translate('View GEDCOM Record'), '#', 'menu-repo-viewraw');
- if (WT_USER_CAN_EDIT) {
- $submenu->addOnclick("return show_gedcom_record('new');");
- } else {
- $submenu->addOnclick("return show_gedcom_record();");
- }
- $menu->addSubmenu($submenu);
- }
-
// delete
if (WT_USER_CAN_EDIT) {
$submenu = new WT_Menu(WT_I18N::translate('Delete'), '#', 'menu-repo-del');
diff --git a/library/WT/Controller/Search.php b/library/WT/Controller/Search.php
index 90a83891a1..ac67d6a0c7 100644
--- a/library/WT/Controller/Search.php
+++ b/library/WT/Controller/Search.php
@@ -285,7 +285,7 @@ class WT_Controller_Search extends WT_Controller_Page {
// Then see if an ID is typed in. If so, we might want to jump there.
if (isset ($this->query)) {
$record=WT_GedcomRecord::getInstance($this->query);
- if ($record && $record->canDisplayDetails()) {
+ if ($record && $record->canShow()) {
header('Location: '.WT_SERVER_NAME.WT_SCRIPT_PATH.$record->getRawUrl());
exit;
}
@@ -357,7 +357,7 @@ class WT_Controller_Search extends WT_Controller_Page {
// If ID cannot be displayed, continue to the search page.
if (count($this->myindilist)==1 && !$this->myfamlist && !$this->mysourcelist && !$this->mynotelist) {
$indi=$this->myindilist[0];
- if ($indi->canDisplayName()) {
+ if ($indi->canShowName()) {
Zend_Session::writeClose();
header('Location: '.WT_SERVER_NAME.WT_SCRIPT_PATH.$indi->getRawUrl());
exit;
@@ -365,7 +365,7 @@ class WT_Controller_Search extends WT_Controller_Page {
}
if (!$this->myindilist && count($this->myfamlist)==1 && !$this->mysourcelist && !$this->mynotelist) {
$fam=$this->myfamlist[0];
- if ($fam->canDisplayName()) {
+ if ($fam->canShowName()) {
Zend_Session::writeClose();
header('Location: '.WT_SERVER_NAME.WT_SCRIPT_PATH.$fam->getRawUrl());
exit;
@@ -373,7 +373,7 @@ class WT_Controller_Search extends WT_Controller_Page {
}
if (!$this->myindilist && !$this->myfamlist && count($this->mysourcelist)==1 && !$this->mynotelist) {
$sour=$this->mysourcelist[0];
- if ($sour->canDisplayName()) {
+ if ($sour->canShowName()) {
Zend_Session::writeClose();
header('Location: '.WT_SERVER_NAME.WT_SCRIPT_PATH.$sour->getRawUrl());
exit;
@@ -381,7 +381,7 @@ class WT_Controller_Search extends WT_Controller_Page {
}
if (!$this->myindilist && !$this->myfamlist && !$this->mysourcelist && count($this->mynotelist)==1) {
$note=$this->mynotelist[0];
- if ($note->canDisplayName()) {
+ if ($note->canShowName()) {
Zend_Session::writeClose();
header('Location: '.WT_SERVER_NAME.WT_SCRIPT_PATH.$note->getRawUrl());
exit;
@@ -443,7 +443,7 @@ class WT_Controller_Search extends WT_Controller_Page {
}
//-- if the record changed replace the record otherwise remove it from the search results
if ($newRecord != $oldRecord) {
- replace_gedrec($individual->getXref(), WT_GED_ID, $newRecord);
+ $individual->updateRecord($newRecord, true);
} else {
unset($this->myindilist[$id]);
}
@@ -465,7 +465,7 @@ class WT_Controller_Search extends WT_Controller_Page {
}
//-- if the record changed replace the record otherwise remove it from the search results
if ($newRecord != $oldRecord) {
- replace_gedrec($family->getXref(), WT_GED_ID, $newRecord);
+ $family->updateRecord($newRecord, true);
} else {
unset($this->myfamlist[$id]);
}
@@ -490,7 +490,7 @@ class WT_Controller_Search extends WT_Controller_Page {
}
//-- if the record changed replace the record otherwise remove it from the search results
if ($newRecord != $oldRecord) {
- replace_gedrec($source->getXref(), WT_GED_ID, $newRecord);
+ $source->updateRecord($newRecord, true);
} else {
unset($this->mysourcelist[$id]);
}
@@ -506,7 +506,7 @@ class WT_Controller_Search extends WT_Controller_Page {
}
//-- if the record changed replace the record otherwise remove it from the search results
if ($newRecord != $oldRecord) {
- replace_gedrec($note->getXref(), WT_GED_ID, $newRecord);
+ $noteource->updateRecord($newRecord, true);
} else {
unset($this->mynotelist[$id]);
}
@@ -557,10 +557,10 @@ class WT_Controller_Search extends WT_Controller_Page {
if ($this->showasso == "on") {
foreach ($this->myindilist as $indi) {
- foreach (fetch_linked_indi($indi->getXref(), 'ASSO', $indi->getGedId()) as $asso) {
+ foreach (fetch_linked_indi($indi->getXref(), 'ASSO', $indi->getGedcomId()) as $asso) {
$this->myindilist[]=$asso;
}
- foreach (fetch_linked_fam($indi->getXref(), 'ASSO', $indi->getGedId()) as $asso) {
+ foreach (fetch_linked_fam($indi->getXref(), 'ASSO', $indi->getGedcomId()) as $asso) {
$this->myfamlist[]=$asso;
}
}
@@ -603,7 +603,7 @@ class WT_Controller_Search extends WT_Controller_Page {
foreach ($this->sgeds as $ged_id=>$gedcom) {
$datalist = array();
foreach ($this->myindilist as $individual) {
- if ($individual->getGedId()==$ged_id) {
+ if ($individual->getGedcomId()==$ged_id) {
$datalist[]=$individual;
}
}
@@ -627,7 +627,7 @@ class WT_Controller_Search extends WT_Controller_Page {
foreach ($this->sgeds as $ged_id=>$gedcom) {
$datalist = array();
foreach ($this->myfamlist as $family) {
- if ($family->getGedId()==$ged_id) {
+ if ($family->getGedcomId()==$ged_id) {
$datalist[]=$family;
}
}
@@ -651,7 +651,7 @@ class WT_Controller_Search extends WT_Controller_Page {
foreach ($this->sgeds as $ged_id=>$gedcom) {
$datalist = array();
foreach ($this->mysourcelist as $source) {
- if ($source->getGedId()==$ged_id) {
+ if ($source->getGedcomId()==$ged_id) {
$datalist[]=$source;
}
}
@@ -675,7 +675,7 @@ class WT_Controller_Search extends WT_Controller_Page {
foreach ($this->sgeds as $ged_id=>$gedcom) {
$datalist = array();
foreach ($this->mynotelist as $note) {
- if ($note->getGedId()==$ged_id) {
+ if ($note->getGedcomId()==$ged_id) {
$datalist[]=$note;
}
}
diff --git a/library/WT/Controller/Source.php b/library/WT/Controller/Source.php
index f2825493d4..dff23a7558 100644
--- a/library/WT/Controller/Source.php
+++ b/library/WT/Controller/Source.php
@@ -2,7 +2,7 @@
// Controller for the source page
//
// webtrees: Web based Family History software
-// Copyright (C) 2012 webtrees development team.
+// Copyright (C) 2013 webtrees development team.
//
// Derived from PhpGedView
// Copyright (C) 2002 to 2010 PGV Development Team. All rights reserved.
@@ -33,35 +33,8 @@ require_once WT_ROOT.'includes/functions/functions_import.php';
class WT_Controller_Source extends WT_Controller_GedcomRecord {
public function __construct() {
- $xref=safe_GET_xref('sid');
-
- $gedrec=find_source_record($xref, WT_GED_ID);
- if (WT_USER_CAN_EDIT) {
- $newrec=find_updated_record($xref, WT_GED_ID);
- } else {
- $newrec=null;
- }
-
- if ($gedrec===null) {
- if ($newrec===null) {
- // Nothing to see here.
- parent::__construct();
- return;
- } else {
- // Create a dummy record from the first line of the new record.
- // We need it for diffMerge(), getXref(), etc.
- list($gedrec)=explode("\n", $newrec);
- }
- }
-
- $this->record = new WT_Source($gedrec);
-
- // If there are pending changes, merge them in.
- if ($newrec!==null) {
- $diff_record=new WT_Source($newrec);
- $diff_record->setChanged(true);
- $this->record->diffMerge($diff_record);
- }
+ $xref = safe_GET_xref('sid');
+ $this->record = WT_Source::getInstance($xref);
parent::__construct();
}
@@ -72,7 +45,7 @@ class WT_Controller_Source extends WT_Controller_GedcomRecord {
function getEditMenu() {
$SHOW_GEDCOM_RECORD=get_gedcom_setting(WT_GED_ID, 'SHOW_GEDCOM_RECORD');
- if (!$this->record || $this->record->isMarkedDeleted()) {
+ if (!$this->record || $this->record->isOld()) {
return null;
}
@@ -85,21 +58,6 @@ class WT_Controller_Source extends WT_Controller_GedcomRecord {
$menu->addSubmenu($submenu);
}
- // edit/view raw gedcom
- if (WT_USER_IS_ADMIN || $SHOW_GEDCOM_RECORD) {
- $submenu = new WT_Menu(WT_I18N::translate('Edit raw GEDCOM record'), '#', 'menu-sour-editraw');
- $submenu->addOnclick("return edit_raw('".$this->record->getXref()."');");
- $menu->addSubmenu($submenu);
- } elseif ($SHOW_GEDCOM_RECORD) {
- $submenu = new WT_Menu(WT_I18N::translate('View GEDCOM Record'), '#', 'menu-sour-viewraw');
- if (WT_USER_CAN_EDIT) {
- $submenu->addOnclick("return show_gedcom_record('new');");
- } else {
- $submenu->addOnclick("return show_gedcom_record();");
- }
- $menu->addSubmenu($submenu);
- }
-
// delete
if (WT_USER_CAN_EDIT) {
$submenu = new WT_Menu(WT_I18N::translate('Delete'), '#', 'menu-sour-del');
diff --git a/library/WT/Controller/Timeline.php b/library/WT/Controller/Timeline.php
index 85f82ea2f7..349a843561 100644
--- a/library/WT/Controller/Timeline.php
+++ b/library/WT/Controller/Timeline.php
@@ -71,7 +71,7 @@ class WT_Controller_Timeline extends WT_Controller_Page {
foreach ($this->pids as $value) {
if ($value!=$remove) {
$newpids[] = $value;
- $person = WT_Person::getInstance($value);
+ $person = WT_Individual::getInstance($value);
if ($person) {
$this->people[] = $person;
}
@@ -81,7 +81,7 @@ class WT_Controller_Timeline extends WT_Controller_Page {
$this->pidlinks = "";
/* @var $indi Person */
foreach ($this->people as $p=>$indi) {
- if (!is_null($indi) && $indi->canDisplayDetails()) {
+ if (!is_null($indi) && $indi->canShow()) {
//-- setup string of valid pids for links
$this->pidlinks .= "pids%5B%5D=".$indi->getXref()."&amp;";
$bdate = $indi->getBirthDate();
@@ -95,8 +95,14 @@ class WT_Controller_Timeline extends WT_Controller_Page {
}
}
// find all the fact information
- $indi->add_family_facts(false);
- foreach ($indi->getIndiFacts() as $event) {
+ $facts = $indi->getFacts();
+ foreach ($indi->getSpouseFamilies() as $family) {
+ foreach ($family->getFacts() as $fact) {
+ $fact->spouse = $family->getSpouse($indi);
+ $facts[] = $fact;
+ }
+ }
+ foreach ($facts as $event) {
//-- get the fact type
$fact = $event->getTag();
if (!in_array($fact, $this->nonfacts)) {
@@ -137,8 +143,8 @@ class WT_Controller_Timeline extends WT_Controller_Page {
$printed = false;
for ($i=0; $i<count($this->people); $i++) {
if (!is_null($this->people[$i])) {
- if (!$this->people[$i]->canDisplayDetails()) {
- if ($this->people[$i]->canDisplayName()) {
+ if (!$this->people[$i]->canShow()) {
+ if ($this->people[$i]->canShowName()) {
echo "&nbsp;<a href=\"".$this->people[$i]->getHtmlUrl()."\">".$this->people[$i]->getFullName()."</a>";
print_privacy_error();
echo "<br>";
@@ -153,15 +159,15 @@ class WT_Controller_Timeline extends WT_Controller_Page {
}
}
- function print_time_fact(WT_Event $event) {
+ function print_time_fact(WT_Fact $event) {
global $basexoffset, $baseyoffset, $factcount, $TEXT_DIRECTION, $WT_IMAGES, $SHOW_PEDIGREE_PLACES, $placements;
/* @var $event Event */
- $factrec = $event->getGedComRecord();
+ $factrec = $event->getGedcom();
$fact = $event->getTag();
- $desc = $event->getDetail();
+ $desc = $event->getValue();
if ($fact=="EVEN" || $fact=="FACT") {
- $fact = $event->getType();
+ $fact = $event->getAttribute('TYPE');
}
//-- check if this is a family fact
$gdate=$event->getDate();
@@ -201,11 +207,11 @@ class WT_Controller_Timeline extends WT_Controller_Page {
echo ": 3px;\">";
$col = $event->temp % 6;
echo "</td><td valign=\"top\" class=\"person".$col."\">";
- if (count($this->pids) > 6) echo $event->getParentObject()->getFullName()." - ";
- $record=$event->getParentObject();
+ if (count($this->pids) > 6) echo $event->getParent()->getFullName()." - ";
+ $record=$event->getParent();
echo $event->getLabel();
echo " -- ";
- if ($record instanceof WT_Person) {
+ if ($record instanceof WT_Individual) {
echo format_fact_date($event, $record, false, false);
} elseif ($record instanceof WT_Family) {
echo $gdate->Display(false);
@@ -242,7 +248,11 @@ class WT_Controller_Timeline extends WT_Controller_Page {
}
}
//-- print spouse name for marriage events
- $spouse = $event->getSpouse();
+ if (isset($event->spouse)) {
+ $spouse = $event->spouse;
+ } else {
+ $spouse = null;
+ }
if ($spouse) {
for ($p=0; $p<count($this->pids); $p++) {
if ($this->pids[$p]==$spouse->getXref()) break;
@@ -252,7 +262,7 @@ class WT_Controller_Timeline extends WT_Controller_Page {
if ($spouse->getXref()!=$this->pids[$p]) {
echo ' <a href="', $spouse->getHtmlUrl(), '">', $spouse->getFullName(), '</a>';
} else {
- echo ' <a href="', $event->getParentObject()->getHtmlUrl(), '">', $event->getParentObject()->getFullName(), '</a>';
+ echo ' <a href="', $event->getParent()->getHtmlUrl(), '">', $event->getParent()->getFullName(), '</a>';
}
}
echo "</td></tr></table>";
@@ -284,7 +294,7 @@ class WT_Controller_Timeline extends WT_Controller_Page {
public function getSignificantIndividual() {
if ($this->pids) {
- return WT_Person::getInstance($this->pids[0]);
+ return WT_Individual::getInstance($this->pids[0]);
} else {
return parent::getSignificantIndividual();
}
diff --git a/library/WT/Event.php b/library/WT/Fact.php
index da786f8d86..8655c76fef 100644
--- a/library/WT/Event.php
+++ b/library/WT/Fact.php
@@ -2,7 +2,7 @@
// Class that defines an event details object
//
// webtrees: Web based Family History software
-// Copyright (C) 2012 webtrees development team.
+// Copyright (C) 2013 webtrees development team.
//
// Derived from PhpGedView
// Copyright (C) 2008 PGV Development Team. All rights reserved.
@@ -28,109 +28,83 @@ if (!defined('WT_WEBTREES')) {
exit;
}
-class WT_Event {
-// These objects need further refinement in their implementations and parsing
-// var $address = null;
-// var $notes = array(); //[0..*]: string
-// var $sourceCitations = array(); //[0..*]: SourceCitation
-// var $multimediaLinks = array(); //[0..*]: MultimediaLink
+class WT_Fact {
+ private $fact_id = null; // Unique identifier for this fact
+ private $parent = null; // The GEDCOM record from which this fact is taken.
+ private $gedcom = null; // The raw GEDCOM data for this fact
+ private $tag = null; // The GEDCOM tag for this record
- var $lineNumber = null;
- var $canShow = null;
- var $state = "";
- var $type = NULL;
- var $tag = NULL;
- var $date = NULL;
- var $place = null;
- var $gedcomRecord = null;
- var $resn = null;
- var $dest = false;
- var $label = null;
- var $parentObject = null;
- var $detail = NULL;
- var $values = NULL;
- var $sortOrder = 0;
- var $sortDate = NULL;
- //-- temporary state variable that can be used by other scripts
- var $temp = NULL;
+ private $is_old = false; // Is this a pending record?
+ private $is_new = false; // Is this a pending record?
- // Is this an old/new pending record?
- private $is_old = false;
- private $is_new = false;
+ private $date = null; // The WT_Date object for the "2 DATE ..." attribute
+ private $place = null; // The WT_Place object for the "2 PLAC ..." attribute
- // For family facts on individual pages - who is the significant spouse.
- private $spouse;
+ // Temporary(!) variables that are used by other scripts
+ public $temp = null; // Timeline controller
+ public $sortOrder = 0; // sort_facts()
- /**
- * Get the value for the first given GEDCOM tag
- *
- * @param string $code
- * @return string
- */
- function getValue($code) {
- if (is_null($this->values)) {
- $this->values=array();
- preg_match_all('/\n2 ('.WT_REGEX_TAG.') (.+)/', $this->gedcomRecord, $matches, PREG_SET_ORDER);
- foreach ($matches as $match) {
- // If this is a link, remove the "@"
- if (preg_match('/^@'.WT_REGEX_XREF.'@$/', $match[2])) {
- $this->values[$match[1]]=trim($match[2], "@");
- } else {
- $this->values[$match[1]]=$match[2];
- }
- }
- }
- if (array_key_exists($code, $this->values)) {
- return $this->values[$code];
+ // Create an event objects from a gedcom fragment.
+ // We need the parent object (to check privacy) and a (pseudo) fact ID to
+ // identify the fact within the record.
+ function __construct($gedcom, WT_GedcomRecord $parent, $fact_id) {
+ if (preg_match('/^1 ('.WT_REGEX_TAG.')/', $gedcom, $match)) {
+ $this->gedcom = $gedcom;
+ $this->parent = $parent;
+ $this->fact_id = $fact_id;
+ $this->tag = $match[1];
+ } else {
+ // TODO need to rewrite code that passes dummy data to this function
+ //throw new Exception('Invalid GEDCOM data passed to WT_Fact::_construct('.$gedcom.')');
}
- return null;
}
- // Create an event objects from a gedcom fragment.
- // We also need to know the parent (to check privacy, etc.) and
- // the line number (from the original, privacy-filtered) gedcom
- // record, to allow editing
- function __construct($subrecord, $parent, $lineNumber) {
- if (preg_match('/^1 ('.WT_REGEX_TAG.') ?(.*)((\n2 CONT.*)*)/', $subrecord, $match)) {
- $this->tag =$match[1];
- $this->detail=$match[2];
- // Some detail records contain multiple lines
- if ($match[3]) {
- $this->detail.=str_replace(array("\n2 CONT ", "\n2 CONT"), "\n", $match[3]);
- }
+ // Get the value of level 1 data in the fact
+ // Allow for multi-line values
+ function getValue() {
+ if (preg_match('/^1 (?:' . $this->tag . ') ?(.*(?:(?:\n2 CONT .*)*))/', $this->gedcom, $match)) {
+ return str_replace("\n2 CONT ", "\n", $match[1]);
} else {
- // We are not ready for this yet.
- // throw new Exception('Invalid GEDCOM data passed to WT_Event::_construct('.$subrecord.')');
+ return null;
}
- $this->gedcomRecord=$subrecord;
- $this->parentObject=$parent;
- $this->lineNumber =$lineNumber;
}
- function setState($s) {
- $this->state = $s;
+ // Get the record to which this fact links
+ function getTarget() {
+ $xref = trim($this->getValue(), '@');
+ switch ($this->tag) {
+ case 'FAMC':
+ case 'FAMS':
+ return WT_Family::getInstance($xref);
+ case 'HUSB':
+ case 'WIFE':
+ case 'CHIL':
+ return WT_Individual::getInstance($xref);
+ case 'SOUR':
+ return WT_Source::getInstance($xref);
+ case 'OBJE':
+ return WT_Media::getInstance($xref);
+ case 'REPO':
+ return WT_Repository::getInstance($xref);
+ case 'NOTE':
+ return WT_Note::getInstance($xref);
+ default:
+ return WT_GedcomRecord::getInstance($xref);
+ }
}
- function getState() {
- return $this->state;
+ // Get the value of level 2 data in the fact
+ function getAttribute($tag) {
+ if (preg_match('/\n2 (?:' . $tag . ') ?(.*(?:(?:\n3 CONT .*)*)*)/', $this->gedcom, $match)) {
+ return str_replace("\n2 CONT ", "\n", $match[1]);
+ } else {
+ return null;
+ }
}
- /**
- * Check whether or not this event can be shown
- *
- * @return boolean
- */
+ // Do the privacy rules allow us to display this fact to the current user
function canShow() {
- if (is_null($this->canShow)) {
- if (empty($this->gedcomRecord)) {
- $this->canShow = false;
- } elseif (!is_null($this->parentObject)) {
- $this->canShow = canDisplayFact($this->parentObject->getXref(), $this->parentObject->getGedId(), $this->gedcomRecord);
- } else {
- $this->canShow = true;
- }
- }
- return $this->canShow;
+ return canDisplayFact($this->parent->getXref(), $this->parent->getGedcomId(), $this->gedcom);
}
// Check whether this fact is protected against edit
@@ -138,92 +112,52 @@ class WT_Event {
// Managers can edit anything
// Members cannot edit RESN, CHAN and locked records
return
- $this->parentObject && $this->parentObject->canEdit() && (
+ $this->parent->canEdit() && !$this->isOld() && (
WT_USER_GEDCOM_ADMIN ||
- WT_USER_CAN_EDIT && strpos($this->gedcomRecord, "\n2 RESN locked")===false && $this->getTag()!='RESN' && $this->getTag()!='CHAN'
+ WT_USER_CAN_EDIT && strpos($this->gedcom, "\n2 RESN locked")===false && $this->getTag()!='RESN' && $this->getTag()!='CHAN'
);
}
- /**
- * The 4 character event type specified by GEDCom.
- *
- * @return string
- */
- function getType() {
- if (is_null($this->type))
- $this->type=$this->getValue('TYPE');
- return $this->type;
- }
-
- /**
- * The place where the event occured.
- *
- * @return string
- */
+ // The place where the event occured.
function getPlace() {
- if (is_null($this->place)) {
- $this->place=$this->getValue('PLAC');
+ if ($this->place === null) {
+ $this->place = $this->getAttribute('PLAC');
}
return $this->place;
}
- // For family facts on individual pages, we need to know the spouse
- public function setSpouse(WT_Person $spouse=null) {
- $this->spouse=$spouse;
- }
- public function getSpouse() {
- return $this->spouse;
- }
-
// We can call this function many times, especially when sorting,
// so keep a copy of the date.
function getDate() {
- if ($this->date===null) {
- $this->date=new WT_Date($this->getValue('DATE'));
+ if ($this->date === null) {
+ $this->date = new WT_Date($this->getAttribute('DATE'));
}
-
return $this->date;
}
- /**
- * The remaining unparsed GEDCom record
- *
- * @return string
- */
- function getGedcomRecord() {
- return $this->gedcomRecord;
+ // The raw GEDCOM data for this fact
+ function getGedcom() {
+ return $this->gedcom;
}
- /**
- * The line number, or line of occurrence in the GEDCom record.
- *
- * @return unknown
- */
- function getLineNumber() {
- return $this->lineNumber;
+ // Unique identifier for the fact
+ function getFactId() {
+ return $this->fact_id;
}
- /**
- *
- */
+ // What sort of fact is this?
function getTag() {
return $this->tag;
}
- /**
- * The Person/Family record where this WT_Event came from
- *
- * @return GedcomRecord
- */
- function getParentObject() {
- return $this->parentObject;
+ // Used to convert a real fact (e.g. BIRT) into a close-relative’s fact (e.g. _BIRT_CHIL)
+ function setTag($tag) {
+ $this->tag = $tag;
}
- /**
- *
- */
- function getDetail() {
- return $this->detail;
+ // The Person/Family record where this WT_Fact came from
+ function getParent() {
+ return $this->parent;
}
function getLabel($abbreviate=false) {
@@ -239,42 +173,39 @@ class WT_Event {
}
// no break - drop into next case
default:
- return WT_Gedcom_Tag::getLabel($this->tag, $this->parentObject);
+ return WT_Gedcom_Tag::getLabel($this->tag, $this->parent);
}
}
}
+ // Is this a pending edit?
public function setIsOld() {
- $this->is_old=true;
- $this->is_new=false;
+ $this->is_old = true;
+ $this->is_new = false;
}
- public function getIsOld() {
+ public function isOld() {
return $this->is_old;
}
public function setIsNew() {
- $this->is_new=true;
- $this->is_old=false;
+ $this->is_new = true;
+ $this->is_old = false;
}
- public function getIsNew() {
+ public function isNew() {
return $this->is_new;
}
- /**
- * Print a simple fact version of this event
- *
- * @param boolean $return whether to print or return
- * @param boolean $anchor whether to add anchor to date and place
- */
+ // Print a simple fact version of this event
function print_simple_fact($return=false, $anchor=false) {
- global $SHOW_PEDIGREE_PLACES, $ABBREVIATE_CHART_LABELS;
+ global $ABBREVIATE_CHART_LABELS;
+
+ $value = $this->getValue();
- if (!$this->canShow()) return "";
$data = '<span class="details_label">'.$this->getLabel($ABBREVIATE_CHART_LABELS).'</span>';
// Don't display "yes", because format_fact_date() does this for us. (Should it?)
- if ($this->detail && $this->detail!='Y') {
- $data .= ' <span dir="auto">'.htmlspecialchars($this->detail).'</span>';
+ if ($value && $value != 'Y') {
+ $data .= ' <span dir="auto">' . htmlspecialchars($value) . '</span>';
}
- $data .= ' '.format_fact_date($this, $this->getParentObject(), $anchor, false);
+ $data .= ' '.format_fact_date($this, $this->getParent(), $anchor, false);
$data .= ' '.format_fact_place($this, $anchor, false, false);
$data .= '<br>';
if ($return) {
@@ -300,13 +231,7 @@ class WT_Event {
}
}
- /**
- * Static Helper functions to sort events
- *
- * @param WT_Event $a
- * @param WT_Event $b
- * @return int
- */
+ // Static Helper functions to sort events
static function CompareDate($a, $b) {
if ($a->getDate()->isOK() && $b->getDate()->isOK()) {
// If both events have dates, compare by date
@@ -326,13 +251,7 @@ class WT_Event {
}
}
- /**
- * Static method to Compare two events by their type
- *
- * @param WT_Event $a
- * @param WT_Event $b
- * @return int
- */
+ // Static method to Compare two events by their type
static function CompareType($a, $b) {
global $factsort;
@@ -398,7 +317,7 @@ class WT_Event {
// Facts from same families stay grouped together
// Keep MARR and DIV from the same families from mixing with events from other FAMs
// Use the original order in which the facts were added
- if ($a->parentObject instanceof WT_Family && $b->parentObject instanceof WT_Family && !$a->parentObject->equals($b->parentObject)) {
+ if ($a->parent instanceof WT_Family && $b->parent instanceof WT_Family && !$a->parent->equals($b->parent)) {
return $a->sortOrder - $b->sortOrder;
}
@@ -423,13 +342,13 @@ class WT_Event {
//-- don't let dated after DEAT/BURI facts sort non-dated facts before DEAT/BURI
//-- treat dated after BURI facts as BURI instead
- if ($a->getValue('DATE')!=NULL && $factsort[$atag]>$factsort['BURI'] && $factsort[$atag]<$factsort['CHAN']) $atag='BURI';
- if ($b->getValue('DATE')!=NULL && $factsort[$btag]>$factsort['BURI'] && $factsort[$btag]<$factsort['CHAN']) $btag='BURI';
+ if ($a->getAttribute('DATE')!=NULL && $factsort[$atag]>$factsort['BURI'] && $factsort[$atag]<$factsort['CHAN']) $atag='BURI';
+ if ($b->getAttribute('DATE')!=NULL && $factsort[$btag]>$factsort['BURI'] && $factsort[$btag]<$factsort['CHAN']) $btag='BURI';
$ret = $factsort[$atag]-$factsort[$btag];
//-- if facts are the same then put dated facts before non-dated facts
if ($ret==0) {
- if ($a->getValue('DATE')!=NULL && $b->getValue('DATE')==NULL) return -1;
- if ($b->getValue('DATE')!=NULL && $a->getValue('DATE')==NULL) return 1;
+ if ($a->getAttribute('DATE')!=NULL && $b->getAttribute('DATE')==NULL) return -1;
+ if ($b->getAttribute('DATE')!=NULL && $a->getAttribute('DATE')==NULL) return 1;
//-- if no sorting preference, then keep original ordering
$ret = $a->sortOrder - $b->sortOrder;
}
diff --git a/library/WT/Family.php b/library/WT/Family.php
index cc7876451c..16193de7fa 100644
--- a/library/WT/Family.php
+++ b/library/WT/Family.php
@@ -30,6 +30,7 @@ if (!defined('WT_WEBTREES')) {
class WT_Family extends WT_GedcomRecord {
const RECORD_TYPE = 'FAM';
+ const SQL_FETCH = "SELECT f_gedcom FROM `##families` WHERE f_id=? AND f_file=?";
const URL_PREFIX = 'family.php?famid=';
private $husb = null;
@@ -37,23 +38,15 @@ class WT_Family extends WT_GedcomRecord {
private $marriage = null;
// Create a Family object from either raw GEDCOM data or a database row
- function __construct($data) {
- if (is_array($data)) {
- // Construct from a row from the database
- if (preg_match('/^1 HUSB @(.+)@/m', $data['gedrec'], $match)) {
- $this->husb=WT_Person::getInstance($match[1]);
- }
- if (preg_match('/^1 WIFE @(.+)@/m', $data['gedrec'], $match)) {
- $this->wife=WT_Person::getInstance($match[1]);
- }
- } else {
- // Construct from raw GEDCOM data
- if (preg_match('/^1 HUSB @(.+)@/m', $data, $match)) {
- $this->husb=WT_Person::getInstance($match[1]);
- }
- if (preg_match('/^1 WIFE @(.+)@/m', $data, $match)) {
- $this->wife=WT_Person::getInstance($match[1]);
- }
+ function __construct($xref, $gedcom, $pending, $gedcom_id) {
+ parent::__construct($xref, $gedcom, $pending, $gedcom_id);
+
+ // TODO: fetch these from WT_Fact objects
+ if (preg_match('/^1 HUSB @(.+)@/m', $gedcom.$pending, $match)) {
+ $this->husb = WT_Individual::getInstance($match[1]);
+ }
+ if (preg_match('/^1 WIFE @(.+)@/m', $gedcom.$pending, $match)) {
+ $this->wife = WT_Individual::getInstance($match[1]);
}
// Make sure husb/wife are the right way round.
@@ -61,7 +54,6 @@ class WT_Family extends WT_GedcomRecord {
list($this->husb, $this->wife)=array($this->wife, $this->husb);
}
- parent::__construct($data);
}
// Generate a private version of this record
@@ -70,10 +62,10 @@ class WT_Family extends WT_GedcomRecord {
$rec='0 @'.$this->xref.'@ FAM';
// Just show the 1 CHIL/HUSB/WIFE tag, not any subtags, which may contain private data
- preg_match_all('/\n1 (?:CHIL|HUSB|WIFE) @('.WT_REGEX_XREF.')@/', $this->_gedrec, $matches, PREG_SET_ORDER);
+ preg_match_all('/\n1 (?:CHIL|HUSB|WIFE) @('.WT_REGEX_XREF.')@/', $this->gedcom, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
- $rela=WT_Person::getInstance($match[1]);
- if ($rela && ($SHOW_PRIVATE_RELATIONSHIPS || $rela->canDisplayDetails($access_level))) {
+ $rela=WT_Individual::getInstance($match[1]);
+ if ($rela && ($SHOW_PRIVATE_RELATIONSHIPS || $rela->canShow($access_level))) {
$rec.=$match[0];
}
}
@@ -81,16 +73,14 @@ class WT_Family extends WT_GedcomRecord {
}
// Fetch the record from the database
- protected static function fetchGedcomRecord($xref, $ged_id) {
+ protected static function fetchGedcomRecord($xref, $gedcom_id) {
static $statement=null;
if ($statement===null) {
- $statement=WT_DB::prepare(
- "SELECT 'FAM' AS type, f_id AS xref, f_file AS ged_id, f_gedcom AS gedrec ".
- "FROM `##families` WHERE f_id=? AND f_file=?"
- );
+ $statement=WT_DB::prepare("SELECT f_gedcom FROM `##families` WHERE f_id=? AND f_file=?");
}
- return $statement->execute(array($xref, $ged_id))->fetchOneRow(PDO::FETCH_ASSOC);
+
+ return $statement->execute(array($xref, $gedcom_id))->fetchOne();
}
/**
@@ -109,12 +99,12 @@ class WT_Family extends WT_GedcomRecord {
}
// Implement family-specific privacy logic
- protected function _canDisplayDetailsByType($access_level) {
+ protected function _canShowByType($access_level) {
// Hide a family if any member is private
- preg_match_all('/\n1 (?:CHIL|HUSB|WIFE) @('.WT_REGEX_XREF.')@/', $this->_gedrec, $matches);
+ preg_match_all('/\n1 (?:CHIL|HUSB|WIFE) @('.WT_REGEX_XREF.')@/', $this->gedcom, $matches);
foreach ($matches[1] as $match) {
- $person=WT_Person::getInstance($match);
- if ($person && !$person->canDisplayDetails($access_level)) {
+ $person=WT_Individual::getInstance($match);
+ if ($person && !$person->canShow($access_level)) {
return false;
}
}
@@ -122,7 +112,7 @@ class WT_Family extends WT_GedcomRecord {
}
// Can the name of this record be shown?
- public function canDisplayName($access_level=WT_USER_ACCESS_LEVEL) {
+ public function canShowName($access_level=WT_USER_ACCESS_LEVEL) {
// We can always see the name (Husband-name + Wife-name), however,
// the name will often be "private + private"
return true;
@@ -137,10 +127,10 @@ class WT_Family extends WT_GedcomRecord {
if (is_null($this->wife) || is_null($this->husb)) {
return null;
}
- if ($this->wife->equals($person) && $this->husb->canDisplayDetails($access_level)) {
+ if ($this->wife->equals($person) && $this->husb->canShow($access_level)) {
return $this->husb;
}
- if ($this->husb->equals($person) && $this->wife->canDisplayDetails($access_level)) {
+ if ($this->husb->equals($person) && $this->wife->canShow($access_level)) {
return $this->wife;
}
return null;
@@ -148,10 +138,10 @@ class WT_Family extends WT_GedcomRecord {
function getSpouses($access_level=WT_USER_ACCESS_LEVEL) {
$spouses=array();
- if ($this->husb && $this->husb->canDisplayDetails($access_level)) {
+ if ($this->husb && $this->husb->canShow($access_level)) {
$spouses[]=$this->husb;
}
- if ($this->wife && $this->wife->canDisplayDetails($access_level)) {
+ if ($this->wife && $this->wife->canShow($access_level)) {
$spouses[]=$this->wife;
}
return $spouses;
@@ -165,10 +155,10 @@ class WT_Family extends WT_GedcomRecord {
global $SHOW_PRIVATE_RELATIONSHIPS;
$children=array();
- preg_match_all('/\n1 CHIL @('.WT_REGEX_XREF.')@/', $this->_gedrec, $match);
+ preg_match_all('/\n1 CHIL @('.WT_REGEX_XREF.')@/', $this->gedcom, $match);
foreach ($match[1] as $pid) {
- $child=WT_Person::getInstance($pid);
- if ($child && ($SHOW_PRIVATE_RELATIONSHIPS || $child->canDisplayDetails($access_level))) {
+ $child=WT_Individual::getInstance($pid);
+ if ($child && ($SHOW_PRIVATE_RELATIONSHIPS || $child->canShow($access_level))) {
$children[]=$child;
}
}
@@ -186,69 +176,23 @@ class WT_Family extends WT_GedcomRecord {
*/
function getNumberOfChildren() {
- $nchi1=(int)get_gedcom_value('NCHI', 1, $this->getGedcomRecord());
- $nchi2=(int)get_gedcom_value('NCHI', 2, $this->getGedcomRecord());
+ $nchi1=(int)get_gedcom_value('NCHI', 1, $this->getGedcom());
+ $nchi2=(int)get_gedcom_value('NCHI', 2, $this->getGedcom());
$nchi3=count($this->getChildren());
return max($nchi1, $nchi2, $nchi3);
}
/**
- * get updated Family
- * If there is an updated family record in the gedcom file
- * return a new family object for it
- */
- function getUpdatedFamily() {
- if ($this->getChanged()) {
- return $this;
- }
- if (WT_USER_CAN_EDIT && $this->canDisplayDetails()) {
- $newrec = find_updated_record($this->xref, $this->ged_id);
- if (!is_null($newrec)) {
- $newfamily = new WT_Family($newrec);
- $newfamily->setChanged(true);
- return $newfamily;
- }
- }
- return null;
- }
- /**
- * check if this family has the given person
- * as a parent in the family
- * @param Person $person
- */
- function hasParent($person) {
- if (is_null($person)) return false;
- if ($person->equals($this->husb)) return true;
- if ($person->equals($this->wife)) return true;
- return false;
- }
- /**
- * check if this family has the given person
- * as a child in the family
- * @param Person $person
- */
- function hasChild($person) {
- if ($person) {
- foreach ($this->getChildren() as $child) {
- if ($person->equals($child)) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
* parse marriage record
*/
function _parseMarriageRecord() {
- $this->marriage = new WT_Event(get_sub_record(1, '1 MARR', $this->getGedcomRecord()), $this, 0);
+ $this->marriage = new WT_Fact(get_sub_record(1, '1 MARR', $this->getGedcom()), $this, 0);
}
/**
* get the marriage event
*
- * @return WT_Event
+ * @return WT_Fact
*/
function getMarriage() {
if (is_null($this->marriage)) $this->_parseMarriageRecord();
@@ -261,17 +205,17 @@ class WT_Family extends WT_GedcomRecord {
*/
function getMarriageRecord() {
if (is_null($this->marriage)) $this->_parseMarriageRecord();
- return $this->marriage->getGedcomRecord();
+ return $this->marriage->getGedcom();
}
// Return whether or not this family ended in a divorce or was never married.
// Note that this is calculated using unprivatized data, so we can
// always distinguish spouses from ex-spouses.
function isDivorced() {
- return (bool)preg_match('/\n1 ('.WT_EVENTS_DIV.')( Y|\n)/', $this->_gedrec);
+ return (bool)preg_match('/\n1 ('.WT_EVENTS_DIV.')( Y|\n)/', $this->gedcom);
}
function isNotMarried() {
- return (bool)preg_match('/\n1 _NMR( Y|\n)/', $this->_gedrec);
+ return (bool)preg_match('/\n1 _NMR( Y|\n)/', $this->gedcom);
}
/**
@@ -279,7 +223,7 @@ class WT_Family extends WT_GedcomRecord {
* @return string
*/
function getMarriageDate() {
- if (!$this->canDisplayDetails()) {
+ if (!$this->canShow()) {
return new WT_Date('');
}
if (is_null($this->marriage)) {
@@ -299,7 +243,7 @@ class WT_Family extends WT_GedcomRecord {
*/
function getMarriageType() {
if (is_null($this->marriage)) $this->_parseMarriageRecord();
- return $this->marriage->getType();
+ return $this->marriage->getAttribute('TYPE');
}
/**
@@ -313,7 +257,7 @@ class WT_Family extends WT_GedcomRecord {
// Get all the dates/places for marriages - for the FAM lists
function getAllMarriageDates() {
- if ($this->canDisplayDetails()) {
+ if ($this->canShow()) {
foreach (explode('|', WT_EVENTS_MARR) as $event) {
if ($array=$this->getAllEventDates($event)) {
return $array;
@@ -323,7 +267,7 @@ class WT_Family extends WT_GedcomRecord {
return array();
}
function getAllMarriagePlaces() {
- if ($this->canDisplayDetails()) {
+ if ($this->canShow()) {
foreach (explode('|', WT_EVENTS_MARR) as $event) {
if ($array=$this->getAllEventPlaces($event)) {
return $array;
@@ -336,8 +280,8 @@ class WT_Family extends WT_GedcomRecord {
// Get an array of structures containing all the names in the record
public function getAllNames() {
if (is_null($this->_getAllNames)) {
- $husb=$this->husb ? $this->husb : new WT_Person('1 SEX M');
- $wife=$this->wife ? $this->wife : new WT_Person('1 SEX F');
+ $husb=$this->husb ? $this->husb : new WT_Individual('M', '1 SEX M', null, $this->gedcom_id);
+ $wife=$this->wife ? $this->wife : new WT_Individual('F', '1 SEX F', null, $this->gedcom_id);
// Check the script used by each name, so we can match cyrillic with cyrillic, greek with greek, etc.
$husb_names=$husb->getAllNames();
foreach ($husb_names as $n=>$husb_name) {
diff --git a/library/WT/Gedcom/Code/Adop.php b/library/WT/Gedcom/Code/Adop.php
index 5a1d9edd79..4b10b4dbcb 100644
--- a/library/WT/Gedcom/Code/Adop.php
+++ b/library/WT/Gedcom/Code/Adop.php
@@ -2,7 +2,7 @@
// Functions and logic for GEDCOM "PEDI" codes
//
// webtrees: Web based Family History software
-// Copyright (C) 2011 webtrees development team.
+// Copyright (C) 2013 webtrees development team.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -31,7 +31,7 @@ class WT_Gedcom_Code_Adop {
// Translate a code, for an (optional) record
public static function getValue($type, $record=null) {
- if ($record instanceof WT_Person) {
+ if ($record instanceof WT_Individual) {
$sex=$record->getSex();
} else {
$sex='U';
diff --git a/library/WT/Gedcom/Code/Name.php b/library/WT/Gedcom/Code/Name.php
index a5ad95f06f..20470b12ed 100644
--- a/library/WT/Gedcom/Code/Name.php
+++ b/library/WT/Gedcom/Code/Name.php
@@ -2,7 +2,7 @@
// Functions and logic for GEDCOM "NAME" codes
//
// webtrees: Web based Family History software
-// Copyright (C) 2011 webtrees development team.
+// Copyright (C) 2013 webtrees development team.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -31,7 +31,7 @@ class WT_Gedcom_Code_Name {
// Translate a code, for an (optional) record
public static function getValue($type, $record=null) {
- if ($record instanceof WT_Person) {
+ if ($record instanceof WT_Individual) {
$sex=$record->getSex();
} else {
$sex='U';
diff --git a/library/WT/Gedcom/Code/Pedi.php b/library/WT/Gedcom/Code/Pedi.php
index 9b8a835ce1..783c59b4f1 100644
--- a/library/WT/Gedcom/Code/Pedi.php
+++ b/library/WT/Gedcom/Code/Pedi.php
@@ -2,7 +2,7 @@
// Functions and logic for GEDCOM "PEDI" codes
//
// webtrees: Web based Family History software
-// Copyright (C) 2012 webtrees development team.
+// Copyright (C) 2013 webtrees development team.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -31,7 +31,7 @@ class WT_Gedcom_Code_Pedi {
// Translate a code, for an optional record
public static function getValue($type, $record=null) {
- if ($record instanceof WT_Person) {
+ if ($record instanceof WT_Individual) {
$sex=$record->getSex();
} else {
$sex='U';
diff --git a/library/WT/Gedcom/Code/Rela.php b/library/WT/Gedcom/Code/Rela.php
index d4faa8f49c..0f53c835b8 100644
--- a/library/WT/Gedcom/Code/Rela.php
+++ b/library/WT/Gedcom/Code/Rela.php
@@ -2,7 +2,7 @@
// Functions and logic for GEDCOM "RELA" codes
//
// webtrees: Web based Family History software
-// Copyright (C) 2011 webtrees development team.
+// Copyright (C) 2013 webtrees development team.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -39,7 +39,7 @@ class WT_Gedcom_Code_Rela {
// Translate a code, for an (optional) record
public static function getValue($type, $record=null) {
- if ($record instanceof WT_Person) {
+ if ($record instanceof WT_Individual) {
$sex=$record->getSex();
} else {
$sex='U';
diff --git a/library/WT/Gedcom/Tag.php b/library/WT/Gedcom/Tag.php
index 83a62af317..d79b92b753 100644
--- a/library/WT/Gedcom/Tag.php
+++ b/library/WT/Gedcom/Tag.php
@@ -2,7 +2,7 @@
// Static GEDCOM data for Tags
//
// webtrees: Web based Family History software
-// Copyright (C) 2012 webtrees development team.
+// Copyright (C) 2013 webtrees development team.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -102,7 +102,7 @@ class WT_Gedcom_Tag {
// Translate a tag, for an (optional) record
public static function getLabel($tag, $record=null) {
- if ($record instanceof WT_Person) {
+ if ($record instanceof WT_Individual) {
$sex=$record->getSex();
} else {
$sex='U';
@@ -879,12 +879,6 @@ class WT_Gedcom_Tag {
return $facts;
}
- // Get a list of reference facts that will be displayed in the "Extra information" sidebar module, and at the same time excluded from the personal_facts module
- public static function getReferenceFacts() {
- return array('CHAN', 'IDNO', 'RFN', 'AFN', 'REFN', 'RIN', '_UID', 'SSN');
- }
-
-
//////////////////////////////////////////////////////////////////////////////
// Definitions for Object, File, Format, Types
//////////////////////////////////////////////////////////////////////////////
diff --git a/library/WT/GedcomRecord.php b/library/WT/GedcomRecord.php
index 2b67f6caa4..67fbca8730 100644
--- a/library/WT/GedcomRecord.php
+++ b/library/WT/GedcomRecord.php
@@ -30,305 +30,265 @@ if (!defined('WT_WEBTREES')) {
class WT_GedcomRecord {
const RECORD_TYPE = 'UNKNOWN';
+ const SQL_FETCH = "SELECT o_gedcom FROM `##other` WHERE o_id=? AND o_file=?";
const URL_PREFIX = 'gedrecord.php?pid=';
- protected $xref =null; // The record identifier
- public $ged_id =null; // The gedcom file, only set if this record comes from the database
- protected $_gedrec =null; // Raw gedcom text (unprivatised)
- private $gedrec =null; // Raw gedcom text (privatised)
- protected $facts =null;
- protected $changeEvent=null;
- private $disp_public=null; // Can we display details of this record to WT_PRIV_PUBLIC
- private $disp_user =null; // Can we display details of this record to WT_PRIV_USER
- private $disp_none =null; // Can we display details of this record to WT_PRIV_NONE
- private $changed =false; // Is this a new record, pending approval
+ protected $xref = null; // The record identifier
+ protected $gedcom_id = null; // The gedcom file
+ protected $gedcom = null; // GEDCOM data (before any pending edits)
+ protected $pending = null; // GEDCOM data (after any pending edits)
- // Cached results from various functions.
- protected $_getAllNames =null;
- protected $_getPrimaryName =null;
- protected $_getSecondaryName=null;
+ protected $facts = null; // Array of WT_Fact objects (from $gedcom/$pending)
- // Create a GedcomRecord object from either raw GEDCOM data or a database row
- public function __construct($data) {
- if (is_array($data)) {
- // Construct from a row from the database
- $this->xref =$data['xref'];
- $this->ged_id =$data['ged_id'];
- $this->_gedrec=$data['gedrec'];
- } else {
- // Construct from raw GEDCOM data
- $this->_gedrec=$data;
- if (preg_match('/^0 (?:@('.WT_REGEX_XREF.')@ )?('.WT_REGEX_TAG.')/', $data, $match)) {
- $this->xref=$match[1];
- $this->ged_id=WT_GED_ID;
- }
- }
- }
+ private $disp_public = null; // Can we display details of this record to WT_PRIV_PUBLIC
+ private $disp_user = null; // Can we display details of this record to WT_PRIV_USER
+ private $disp_none = null; // Can we display details of this record to WT_PRIV_NONE
- // Get an instance of a GedcomRecord. We either specify
- // an XREF (in the current gedcom), or we can provide a row
- // from the database (if we anticipate the record hasn't
- // been fetched previously).
- static public function getInstance($data) {
- global $gedcom_record_cache, $GEDCOM;
- static $pending_record_cache;
+ // Cached results from various functions.
+ protected $_getAllNames = null;
+ protected $_getPrimaryName = null;
+ protected $_getSecondaryName = null;
+
+ // Allow getInstance() to return references to existing objects
+ private static $gedcom_record_cache;
+ // Fetch all pending edits in one database query
+ private static $pending_record_cache;
- $is_pending=false; // Did this record come from a pending edit
+ // Create a GedcomRecord object from raw GEDCOM data.
+ // $gedcom is an empty string for new/pending records
+ // $pending is null for a record with no pending edits
+ // $pending is an empty string for records with pending deletions
+ public function __construct($xref, $gedcom, $pending, $gedcom_id) {
+ $this->xref = $xref;
+ $this->gedcom = $gedcom;
+ $this->pending = $pending;
+ $this->gedcom_id = $gedcom_id;
- if (is_array($data)) {
- $ged_id=$data['ged_id'];
- $pid =$data['xref'];
+ // Split the record into facts
+ if ($gedcom) {
+ $gedcom_facts = preg_split('/\n(?=1)/s', $gedcom);
+ array_shift($gedcom_facts);
+ } else {
+ $gedcom_facts = array();
+ }
+ if ($pending) {
+ $pending_facts = preg_split('/\n(?=1)/s', $pending);
+ array_shift($pending_facts);
} else {
- $ged_id=get_id_from_gedcom($GEDCOM);
- $pid =$data;
+ $pending_facts = array();
}
- // Check the cache first
- if (isset($gedcom_record_cache[$pid][$ged_id])) {
- return $gedcom_record_cache[$pid][$ged_id];
+ $this->facts = array();
+
+ foreach ($gedcom_facts as $gedcom_fact) {
+ $fact = new WT_Fact($gedcom_fact, $this, md5($gedcom_fact));
+ if ($pending !== null && !in_array($gedcom_fact, $pending_facts)) {
+ $fact->setIsOld();
+ }
+ $this->facts[] = $fact;
+ }
+ foreach ($pending_facts as $pending_fact) {
+ if (!in_array($pending_fact, $gedcom_facts)) {
+ $fact = new WT_Fact($pending_fact, $this, md5($pending_fact));
+ $fact->setIsNew();
+ $this->facts[] = $fact;
+ }
}
+ }
- // Look for the record in the database
- if (!is_array($data)) {
- $data=static::fetchGedcomRecord($pid, $ged_id);
+ // Get an instance of a GedcomRecord object. For single records,
+ // we just receive the XREF. For bulk records (such as lists
+ // and search results) we can receive the GEDCOM data as well.
+ static public function getInstance($xref, $gedcom_id=WT_GED_ID, $gedcom=null) {
+ // Is this record already in the cache?
+ if (isset(self::$gedcom_record_cache[$xref][$gedcom_id])) {
+ return self::$gedcom_record_cache[$xref][$gedcom_id];
+ }
- // If we can edit, then we also need to be able to see pending records.
- // Otherwise relationship privacy rules will not allow us to see
- // newly added records.
- if (WT_USER_CAN_EDIT) {
- if (!isset($pending_record_cache[$ged_id])) {
- // Fetch all pending records in one database query
- $pending_record_cache[$ged_id]=array();
- $rows = WT_DB::prepare(
- "SELECT xref, new_gedcom FROM `##change` WHERE status='pending' AND gedcom_id=?"
- )->execute(array($ged_id))->fetchAll();
- foreach ($rows as $row) {
- $pending_record_cache[$ged_id][$row->xref] = $row->new_gedcom;
- }
- }
+ // Do we need to fetch the record from the database?
+ if ($gedcom === null) {
+ $gedcom = static::fetchGedcomRecord($xref, $gedcom_id);
+ }
- if (isset($pending_record_cache[$ged_id][$pid])) {
- // A pending edit exists for this record
- $tmp = $pending_record_cache[$ged_id][$pid];
- // $tmp can be an empty string, indicating the record has
- // a pending deletion. Ignore this, as we handle pending
- // deletions separately.
- if ($tmp) {
- $is_pending=true;
- $data=$tmp;
- }
+ // If we can edit, then we also need to be able to see pending records.
+ if (WT_USER_CAN_EDIT) {
+ if (!isset(self::$pending_record_cache[$gedcom_id])) {
+ // Fetch all pending records in one database query
+ self::$pending_record_cache[$gedcom_id]=array();
+ $rows = WT_DB::prepare(
+ "SELECT xref, new_gedcom FROM `##change` WHERE status='pending' AND gedcom_id=?"
+ )->execute(array($gedcom_id))->fetchAll();
+ foreach ($rows as $row) {
+ self::$pending_record_cache[$gedcom_id][$row->xref] = $row->new_gedcom;
}
}
- // If we still didn't find it, it doesn't exist
- if (!$data) {
- return null;
+ if (isset(self::$pending_record_cache[$gedcom_id][$xref])) {
+ // A pending edit exists for this record
+ $pending = self::$pending_record_cache[$gedcom_id][$xref];
+ } else {
+ $pending = null;
}
+ } else {
+ // There are no pending changes for this record
+ $pending = null;
+ }
+
+ // No such record exists
+ if ($gedcom === null && $pending === null) {
+ return null;
}
// Create the object
- if (is_array($data)) {
- $type=$data['type'];
- } elseif (preg_match('/^0 @'.WT_REGEX_XREF.'@ ('.WT_REGEX_TAG.')/', $data, $match)) {
- $type=$match[1];
+ if (preg_match('/^0 @' . WT_REGEX_XREF . '@ (' . WT_REGEX_TAG . ')/', $gedcom.$pending, $match)) {
+ $type = $match[1];
} else {
- $type='';
+ throw new Exception('Unrecognised GEDCOM record: ' . $gedcom);
}
+
switch($type) {
case 'INDI':
- $object=new WT_Person($data);
+ $record = new WT_Individual($xref, $gedcom, $pending, $gedcom_id);
break;
case 'FAM':
- $object=new WT_Family($data);
+ $record = new WT_Family($xref, $gedcom, $pending, $gedcom_id);
break;
case 'SOUR':
- $object=new WT_Source($data);
+ $record = new WT_Source($xref, $gedcom, $pending, $gedcom_id);
break;
case 'OBJE':
- $object=new WT_Media($data);
+ $record = new WT_Media($xref, $gedcom, $pending, $gedcom_id);
break;
case 'REPO':
- $object=new WT_Repository($data);
+ $record = new WT_Repository($xref, $gedcom, $pending, $gedcom_id);
break;
case 'NOTE':
- $object=new WT_Note($data);
+ $record = new WT_Note($xref, $gedcom, $pending, $gedcom_id);
break;
default:
- $object=new WT_GedcomRecord($data);
- break;
- }
-
- // This is an object from the database, so indicate which gedcom it comes from.
- $object->ged_id=$ged_id;
-
- if ($is_pending) {
- $object->setChanged(true);
+ throw new Exception('No support for GEDCOM record type: ' . $type);
}
// Store it in the cache
- $gedcom_record_cache[$object->xref][$object->ged_id]=&$object;
- return $object;
+ self::$gedcom_record_cache[$xref][$gedcom_id] = $record;
+
+ return $record;
}
- private static function fetchGedcomRecord($xref, $ged_id) {
+ private static function fetchGedcomRecord($xref, $gedcom_id) {
static $statement=null;
// We don't know what type of object this is. Try each one in turn.
- $row=WT_Person::fetchGedcomRecord($xref, $ged_id);
- if ($row) {
- return $row;
+ $data = WT_Individual::fetchGedcomRecord($xref, $gedcom_id);
+ if ($data) {
+ return $data;
}
- $row=WT_Family::fetchGedcomRecord($xref, $ged_id);
- if ($row) {
- return $row;
+ $data = WT_Family::fetchGedcomRecord($xref, $gedcom_id);
+ if ($data) {
+ return $data;
}
- $row=WT_Source::fetchGedcomRecord($xref, $ged_id);
- if ($row) {
- return $row;
+ $data = WT_Source::fetchGedcomRecord($xref, $gedcom_id);
+ if ($data) {
+ return $data;
}
- $row=WT_Repository::fetchGedcomRecord($xref, $ged_id);
- if ($row) {
- return $row;
+ $data = WT_Repository::fetchGedcomRecord($xref, $gedcom_id);
+ if ($data) {
+ return $data;
}
- $row=WT_Media::fetchGedcomRecord($xref, $ged_id);
- if ($row) {
- return $row;
+ $data = WT_Media::fetchGedcomRecord($xref, $gedcom_id);
+ if ($data) {
+ return $data;
}
- $row=WT_Note::fetchGedcomRecord($xref, $ged_id);
- if ($row) {
- return $row;
+ $data = WT_Note::fetchGedcomRecord($xref, $gedcom_id);
+ if ($data) {
+ return $data;
}
// Some other type of record...
if (is_null($statement)) {
- $statement=WT_DB::prepare(
- "SELECT o_type AS type, o_id AS xref, o_file AS ged_id, o_gedcom AS gedrec ".
- "FROM `##other` WHERE o_id=? AND o_file=? AND o_type NOT IN ('REPO', 'NOTE')"
- );
+ $statement=WT_DB::prepare("SELECT o_gedcom FROM `##other` WHERE o_id=? AND o_file=?");
}
- return $statement->execute(array($xref, $ged_id))->fetchOneRow(PDO::FETCH_ASSOC);
+ return $statement->execute(array($xref, $gedcom_id))->fetchOne();
}
- /**
- * get the xref
- * @return string returns the person ID
- */
+ // XREF
public function getXref() {
return $this->xref;
}
- /**
- * get the gedcom file
- * @return string returns the person ID
- */
- public function getGedId() {
- return $this->ged_id;
+
+ // GEDCOM ID
+ public function getGedcomId() {
+ return $this->gedcom_id;
}
- /**
- * get gedcom record
- */
- public function getGedcomRecord() {
- if ($this->gedrec===null) {
- list($this->gedrec)=$this->privatizeGedcom(WT_USER_ACCESS_LEVEL);
+ // Application code should access data via WT_Fact objects
+ public function getGedcom() {
+ if ($this->pending === null) {
+ return $this->gedcom;
+ } else {
+ return $this->pending;
}
- return $this->gedrec;
- }
- /**
- * set gedcom record
- */
- public function setGedcomRecord($gcRec) {
- $this->gedrec = $gcRec;
}
- /**
- * set if this is a changed record from the gedcom file
- * @param boolean $changed
- */
- public function setChanged($changed) {
- $this->changed = $changed;
+
+ // Does this record have a pending change?
+ public function isNew() {
+ return $this->pending !== null;
}
- /**
- * get if this is a changed record from the gedcom file
- * @return boolean
- */
- public function getChanged() {
- return $this->changed;
+
+ // Does this record have a pending deletion?
+ public function isOld() {
+ return $this->pending === '';
}
- /**
- * check if this object is equal to the given object
- * @param GedcomRecord $obj
- */
+ // Are two records the same?
public function equals($obj) {
- return !is_null($obj) && $this->xref==$obj->getXref();
+ return $obj && $this->xref==$obj->getXref();
}
- // Generate a URL to this record, suitable for use in HTML
+ // Generate a URL to this record, suitable for use in HTML, etc.
public function getHtmlUrl() {
- return self::_getLinkUrl(static::URL_PREFIX, '&amp;');
+ return $this->_getLinkUrl(static::URL_PREFIX, '&amp;');
}
// Generate a URL to this record, suitable for use in javascript, HTTP headers, etc.
public function getRawUrl() {
- return self::_getLinkUrl(static::URL_PREFIX, '&');
+ return $this->_getLinkUrl(static::URL_PREFIX, '&');
}
- private function _getLinkUrl($link, $separator) {
- if ($this->ged_id) {
- // If the record was created from the database, we know the gedcom
- return $link.$this->getXref().$separator.'ged='.rawurlencode(get_gedcom_from_id($this->ged_id));
- } else {
- // If the record was created from a text string, assume the current gedcom
- return $link.$this->getXref().$separator.'ged='.WT_GEDURL;
- }
- }
-
- /**
- * return an absolute url for linking to this record from another site
- *
- */
+ // Generate an absolute URL for this record, suitable for sitemap.xml, RSS feeds, etc.
public function getAbsoluteLinkUrl() {
- return WT_SERVER_NAME.WT_SCRIPT_PATH.$this->getHtmlUrl();
+ return WT_SERVER_NAME . WT_SCRIPT_PATH . $this->getHtmlUrl();
}
- /**
- * check if this record has been marked for deletion
- * @return boolean
- */
- public function isMarkedDeleted() {
- $tmp=WT_DB::prepare(
- "SELECT new_gedcom".
- " FROM `##change`".
- " WHERE status='pending' AND gedcom_id=? AND xref=?".
- " ORDER BY change_id desc".
- " LIMIT 1"
- )->execute(array($this->ged_id, $this->xref))->fetchOne();
-
- return $tmp==='';
+ private function _getLinkUrl($link, $separator) {
+ if ($this->gedcom_id == WT_GED_ID) {
+ return $link . $this->getXref() . $separator . 'ged=' . WT_GEDURL;
+ } else {
+ return $link . $this->getXref() . $separator . 'ged=' . rawurlencode(get_gedcom_from_id($this->gedcom_id));
+ }
}
// Work out whether this record can be shown to a user with a given access level
- private function _canDisplayDetails($access_level) {
- global $person_privacy, $HIDE_LIVE_PEOPLE, $PRIVACY_CHECKS;
+ private function _canShow($access_level) {
+ global $person_privacy, $HIDE_LIVE_PEOPLE;
- //-- keep a count of how many times we have checked for privacy
- ++$PRIVACY_CHECKS;
// This setting would better be called "$ENABLE_PRIVACY"
if (!$HIDE_LIVE_PEOPLE) {
return true;
}
// We should always be able to see our own record (unless an admin is applying download restrictions)
- if ($this->getXref()==WT_USER_GEDCOM_ID && $this->getGedId()==WT_GED_ID && $access_level==WT_USER_ACCESS_LEVEL) {
+ if ($this->getXref()==WT_USER_GEDCOM_ID && $this->getGedcomId()==WT_GED_ID && $access_level==WT_USER_ACCESS_LEVEL) {
return true;
}
// Does this record have a RESN?
- if (strpos($this->_gedrec, "\n1 RESN confidential")) {
+ if (strpos($this->gedcom, "\n1 RESN confidential")) {
return WT_PRIV_NONE>=$access_level;
}
- if (strpos($this->_gedrec, "\n1 RESN privacy")) {
+ if (strpos($this->gedcom, "\n1 RESN privacy")) {
return WT_PRIV_USER>=$access_level;
}
- if (strpos($this->_gedrec, "\n1 RESN none")) {
+ if (strpos($this->gedcom, "\n1 RESN none")) {
return true;
}
@@ -343,11 +303,11 @@ class WT_GedcomRecord {
}
// Different types of record have different privacy rules
- return $this->_canDisplayDetailsByType($access_level);
+ return $this->_canShowByType($access_level);
}
// Each object type may have its own special rules, and re-implement this function.
- protected function _canDisplayDetailsByType($access_level) {
+ protected function _canShowByType($access_level) {
global $global_facts;
if (isset($global_facts[static::RECORD_TYPE])) {
@@ -360,23 +320,23 @@ class WT_GedcomRecord {
}
// Can the details of this record be shown?
- public function canDisplayDetails($access_level=WT_USER_ACCESS_LEVEL) {
+ public function canShow($access_level=WT_USER_ACCESS_LEVEL) {
// CACHING: this function can take three different parameters,
// and therefore needs three different caches for the result.
switch ($access_level) {
case WT_PRIV_PUBLIC: // visitor
if ($this->disp_public===null) {
- $this->disp_public=$this->_canDisplayDetails(WT_PRIV_PUBLIC);
+ $this->disp_public=$this->_canShow(WT_PRIV_PUBLIC);
}
return $this->disp_public;
case WT_PRIV_USER: // member
if ($this->disp_user===null) {
- $this->disp_user=$this->_canDisplayDetails(WT_PRIV_USER);
+ $this->disp_user=$this->_canShow(WT_PRIV_USER);
}
return $this->disp_user;
case WT_PRIV_NONE: // admin
if ($this->disp_none===null) {
- $this->disp_none=$this->_canDisplayDetails(WT_PRIV_NONE);
+ $this->disp_none=$this->_canShow(WT_PRIV_NONE);
}
return $this->disp_none;
case WT_PRIV_HIDE: // hidden from admins
@@ -390,15 +350,13 @@ class WT_GedcomRecord {
}
// Can the name of this record be shown?
- public function canDisplayName($access_level=WT_USER_ACCESS_LEVEL) {
- return $this->canDisplayDetails($access_level);
+ public function canShowName($access_level=WT_USER_ACCESS_LEVEL) {
+ return $this->canShow($access_level);
}
// Can we edit this record?
- // We use the unprivatized _gedrec as we must take account
- // of the RESN tag, even if we are not permitted to see it.
public function canEdit() {
- return WT_USER_GEDCOM_ADMIN || WT_USER_CAN_EDIT && strpos($this->_gedrec, "\n1 RESN locked")===false;
+ return WT_USER_GEDCOM_ADMIN || WT_USER_CAN_EDIT && strpos($this->gedcom, "\n1 RESN locked")===false;
}
// Remove private data from the raw gedcom record.
@@ -408,28 +366,25 @@ class WT_GedcomRecord {
if ($access_level==WT_PRIV_HIDE) {
// We may need the original record, for example when downloading a GEDCOM or clippings cart
- return array($this->_gedrec, '');
- } elseif ($this->canDisplayDetails($access_level)) {
+ return array($this->gedcom, '');
+ } elseif ($this->canShow($access_level)) {
// The record is not private, but the individual facts may be.
// Include the entire first line (for NOTE records)
- list($gedrec)=explode("\n", $this->_gedrec, 2);
+ list($gedrec)=explode("\n", $this->gedcom, 2);
- $private_gedrec='';
// Check each of the sub facts for access
- preg_match_all('/\n1 .*(?:\n[2-9].*)*/', $this->_gedrec, $matches);
+ preg_match_all('/\n1 .*(?:\n[2-9].*)*/', $this->gedcom, $matches);
foreach ($matches[0] as $match) {
- if (canDisplayFact($this->xref, $this->ged_id, $match, $access_level)) {
+ if (canDisplayFact($this->xref, $this->gedcom_id, $match, $access_level)) {
$gedrec.=$match;
- } else {
- $private_gedrec.=$match;
}
}
- return array($gedrec, $private_gedrec);
+ return $gedrec;
} else {
// We cannot display the details, but we may be able to display
// limited data, such as links to other records.
- return array($this->createPrivateGedcomRecord($access_level), '');
+ return $this->createPrivateGedcomRecord($access_level);
}
}
@@ -440,10 +395,10 @@ class WT_GedcomRecord {
// Convert a name record into sortable and full/display versions. This default
// should be OK for simple record types. INDI/FAM records will need to redefine it.
- protected function _addName($type, $value, $gedrec) {
+ protected function _addName($type, $value, $gedcom) {
$this->_getAllNames[]=array(
'type'=>$type,
- 'sort'=>preg_replace('/([0-9]+)/e', 'substr("000000000\\1", -10)', $value),
+ 'sort'=>preg_replace_callback('/([0-9]+)/', function($matches) { return str_pad($matches[0], 10, '0', STR_PAD_LEFT); }, $value),
'full'=>'<span dir="auto">'.htmlspecialchars($value).'</span>', // This is used for display
'fullNN'=>$value, // This goes into the database
);
@@ -462,10 +417,10 @@ class WT_GedcomRecord {
if (is_null($this->_getAllNames)) {
$this->_getAllNames=array();
- if ($this->canDisplayName()) {
+ if ($this->canShowName()) {
$sublevel=$level+1;
$subsublevel=$sublevel+1;
- if (preg_match_all("/^{$level} ({$fact}) (.+)((\n[{$sublevel}-9].+)*)/m", $this->getGedcomRecord(), $matches, PREG_SET_ORDER)) {
+ if (preg_match_all("/^{$level} ({$fact}) (.+)((\n[{$sublevel}-9].+)*)/m", $this->getGedcom(), $matches, PREG_SET_ORDER)) {
foreach ($matches as $match) {
// Treat 1 NAME / 2 TYPE married the same as _MARNM
if ($match[1]=='NAME' && strpos($match[3], "\n2 TYPE married")!==false) {
@@ -581,20 +536,20 @@ class WT_GedcomRecord {
// Allow native PHP functions such as array_intersect() to work with objects
public function __toString() {
- return $this->xref.'@'.$this->ged_id;
+ return $this->xref.'@'.$this->gedcom_id;
}
// Static helper function to sort an array of objects by name
// Records whose names cannot be displayed are sorted at the end.
static function Compare($x, $y) {
- if ($x->canDisplayName()) {
- if ($y->canDisplayName()) {
+ if ($x->canShowName()) {
+ if ($y->canShowName()) {
return utf8_strcasecmp($x->getSortName(), $y->getSortName());
} else {
return -1; // only $y is private
}
} else {
- if ($y->canDisplayName()) {
+ if ($y->canShowName()) {
return 1; // only $x is private
} else {
return 0; // both $x and $y private
@@ -611,8 +566,8 @@ class WT_GedcomRecord {
return $tmp;
} else {
if (
- preg_match('/^\d\d:\d\d:\d\d/', get_gedcom_value('DATE:TIME', 2, $chan_x->getGedcomRecord()).':00', $match_x) &&
- preg_match('/^\d\d:\d\d:\d\d/', get_gedcom_value('DATE:TIME', 2, $chan_y->getGedcomRecord()).':00', $match_y)
+ preg_match('/^\d\d:\d\d:\d\d/', get_gedcom_value('DATE:TIME', 2, $chan_x->getGedcom()).':00', $match_x) &&
+ preg_match('/^\d\d:\d\d:\d\d/', get_gedcom_value('DATE:TIME', 2, $chan_y->getGedcom()).':00', $match_y)
) {
return strcmp($match_x[0], $match_y[0]);
} else {
@@ -623,22 +578,22 @@ class WT_GedcomRecord {
// Get variants of the name
public function getFullName() {
- if ($this->canDisplayName()) {
- $tmp=$this->getAllNames();
+ if ($this->canShowName()) {
+ $tmp = $this->getAllNames();
return $tmp[$this->getPrimaryName()]['full'];
} else {
return WT_I18N::translate('Private');
}
}
public function getSortName() {
- // The sortable name is never displayed, no need to call canDisplayName()
- $tmp=$this->getAllNames();
+ // The sortable name is never displayed, no need to call canShowName()
+ $tmp = $this->getAllNames();
return $tmp[$this->getPrimaryName()]['sort'];
}
// Get the fullname in an alternative character set
public function getAddName() {
- if ($this->canDisplayName() && $this->getPrimaryName()!=$this->getSecondaryName()) {
- $all_names=$this->getAllNames();
+ if ($this->canShowName() && $this->getPrimaryName()!=$this->getSecondaryName()) {
+ $all_names = $this->getAllNames();
return $all_names[$this->getSecondaryName()]['full'];
} else {
return null;
@@ -672,7 +627,7 @@ class WT_GedcomRecord {
// Extract/format the first fact from a list of facts.
public function format_first_major_fact($facts, $style) {
- foreach ($this->getAllFactsByType(explode('|', $facts)) as $event) {
+ foreach ($this->getFacts($facts) as $event) {
// Only display if it has a date or place (or both)
if (($event->getDate()->isOK() || $event->getPlace()) && $event->canShow()) {
switch ($style) {
@@ -688,22 +643,22 @@ class WT_GedcomRecord {
// Fetch the records that link to this one
public function fetchLinkedIndividuals() {
- return fetch_linked_indi($this->getXref(), static::RECORD_TYPE, $this->ged_id);
+ return fetch_linked_indi($this->getXref(), static::RECORD_TYPE, $this->gedcom_id);
}
public function fetchLinkedFamilies() {
- return fetch_linked_fam($this->getXref(), static::RECORD_TYPE, $this->ged_id);
+ return fetch_linked_fam($this->getXref(), static::RECORD_TYPE, $this->gedcom_id);
}
public function fetchLinkedNotes() {
- return fetch_linked_note($this->getXref(), static::RECORD_TYPE, $this->ged_id);
+ return fetch_linked_note($this->getXref(), static::RECORD_TYPE, $this->gedcom_id);
}
public function fetchLinkedSources() {
- return fetch_linked_sour($this->getXref(), static::RECORD_TYPE, $this->ged_id);
+ return fetch_linked_sour($this->getXref(), static::RECORD_TYPE, $this->gedcom_id);
}
public function fetchLinkedRepositories() {
- return fetch_linked_repo($this->getXref(), static::RECORD_TYPE, $this->ged_id);
+ return fetch_linked_repo($this->getXref(), static::RECORD_TYPE, $this->gedcom_id);
}
public function fetchLinkedMedia() {
- return fetch_linked_obje($this->getXref(), static::RECORD_TYPE, $this->ged_id);
+ return fetch_linked_obje($this->getXref(), static::RECORD_TYPE, $this->gedcom_id);
}
// Get all attributes (e.g. DATE or PLAC) from an event (e.g. BIRT or MARR).
@@ -712,154 +667,48 @@ class WT_GedcomRecord {
// calendars, place-names in both latin and hebrew character sets, etc.
// It also allows us to combine dates/places from different events in the summaries.
public function getAllEventDates($event) {
- $dates=array();
- foreach ($this->getAllFactsByType($event) as $event) {
+ $dates = array();
+ foreach ($this->getFacts($event) as $event) {
if ($event->getDate()->isOK()) {
- $dates[]=$event->getDate();
+ $dates[] = $event->getDate();
}
}
return $dates;
}
public function getAllEventPlaces($event) {
- $places=array();
- foreach ($this->getAllFactsByType($event) as $event) {
- if (preg_match_all('/\n(?:2 PLAC|3 (?:ROMN|FONE|_HEB)) +(.+)/', $event->getGedcomRecord(), $ged_places)) {
+ $places = array();
+ foreach ($this->getFacts($event) as $event) {
+ if (preg_match_all('/\n(?:2 PLAC|3 (?:ROMN|FONE|_HEB)) +(.+)/', $event->getGedcom(), $ged_places)) {
foreach ($ged_places[1] as $ged_place) {
- $places[]=$ged_place;
+ $places[] = $ged_place;
}
}
}
return $places;
}
- // Get the first WT_Event for the given fact type
+ // Get the first WT_Fact for the given fact type
public function getFactByType($tag) {
foreach ($this->getFacts() as $fact) {
- if ($fact->getTag()==$tag) {
+ if ($fact->getTag() == $tag) {
return $fact;
}
}
return null;
}
- // Return an array of events that match the given types
- public function getAllFactsByType($tags) {
- if (is_string($tags)) {
- $tags = array($tags);
- }
- $facts = array();
- foreach ($tags as $tag) {
- foreach ($this->getFacts() as $fact) {
- if ($fact->getTag()==$tag) {
- $facts[]=$fact;
- }
- }
- }
- return $facts;
- }
-
- /**
- * returns an array of all of the facts
- * @return Array
- */
- public function getFacts() {
- $this->parseFacts();
- return $this->facts;
- }
-
- /**
- * Get the CHAN event for this record
- *
- * @return WT_Event
- */
- public function getChangeEvent() {
- if (is_null($this->changeEvent)) {
- $this->changeEvent = $this->getFactByType('CHAN');
- }
- return $this->changeEvent;
- }
-
- /**
- * Parse the facts from the record
- */
- public function parseFacts() {
- //-- only run this function once
- if (!is_null($this->facts) && is_array($this->facts)) {
- return;
- }
- $this->facts=array();
- //-- don't run this function if privacy does not allow viewing of details
- if (!$this->canDisplayDetails()) {
- return;
- }
- //-- find all the fact information
- $indilines = explode("\n", $this->getGedcomRecord()); // -- find the number of lines in the individuals record
- $lct = count($indilines);
- $factrec = ''; // -- complete fact record
- $line = ''; // -- temporary line buffer
- $linenum=1;
- for ($i=1; $i<=$lct; $i++) {
- if ($i<$lct) {
- $line = $indilines[$i];
- } else {
- $line=' ';
- }
- if (empty($line)) {
- $line=' ';
- }
- if ($i==$lct||$line{0}==1) {
- if ($i>1) {
- $this->facts[] = new WT_Event($factrec, $this, $linenum);
- }
- $factrec = $line;
- $linenum = $i;
- }
- else $factrec .= "\n".$line;
- }
- }
-
- /**
- * Merge the facts from another GedcomRecord object into this object
- * for generating a diff view
- * @param GedcomRecord $diff the record to compare facts with
- */
- public function diffMerge($diff) {
- if (is_null($diff)) {
- return;
- }
- $this->parseFacts();
- $diff->parseFacts();
-
- //-- update old facts
- foreach ($this->facts as $key=>$event) {
- $found = false;
- foreach ($diff->facts as $indexval => $newevent) {
- $newfact = $newevent->getGedcomRecord();
- $newfact=preg_replace("/\\\/", '/', $newfact);
- if (trim($newfact)==trim($event->getGedcomRecord())) {
- $found = true;
- break;
- }
- }
- if (!$found) {
- $this->facts[$key]->setIsOld();
- }
- }
- //-- look for new facts
- foreach ($diff->facts as $key=>$newevent) {
- $found = false;
- foreach ($this->facts as $indexval => $event) {
- $newfact = $newevent->getGedcomRecord();
- $newfact=preg_replace("/\\\/", '/', $newfact);
- if (trim($newfact)==trim($event->getGedcomRecord())) {
- $found = true;
- break;
+ // The facts and events for this record
+ public function getFacts($filter=null) {
+ if ($filter === null) {
+ return $this->facts;
+ } else {
+ $facts=array();
+ foreach ($this->facts as $fact) {
+ if (preg_match('/^' . $filter . '$/', $fact->getTag())) {
+ $facts[] = $fact;
}
}
- if (!$found) {
- $newevent->setIsNew();
- $this->facts[]=$newevent;
- }
+ return $facts;
}
}
@@ -871,26 +720,18 @@ class WT_GedcomRecord {
$srec = $srec[0];
return get_gedcom_value('DATE', 2, $srec);
}
- public function getEventSource($event) {
- $srec = $this->getAllEvents($event);
- if (!$srec) {
- return '';
- }
- $srec = $srec[0];
- return get_sub_record('SOUR', 2, $srec);
- }
//////////////////////////////////////////////////////////////////////////////
// Get the last-change timestamp for this record, either as a formatted string
// (for display) or as a unix timestamp (for sorting)
//////////////////////////////////////////////////////////////////////////////
public function LastChangeTimestamp($sorting=false) {
- $chan = $this->getChangeEvent();
+ $chan = $this->getFactByType('CHAN');
if ($chan) {
// The record does have a CHAN event
$d = $chan->getDate()->MinDate();
- if (preg_match('/^(\d\d):(\d\d):(\d\d)/', get_gedcom_value('DATE:TIME', 2, $chan->getGedcomRecord()).':00', $match)) {
+ if (preg_match('/^(\d\d):(\d\d):(\d\d)/', get_gedcom_value('DATE:TIME', 2, $chan->getGedcom()).':00', $match)) {
$t=mktime((int)$match[1], (int)$match[2], (int)$match[3], (int)$d->Format('%n'), (int)$d->Format('%j'), (int)$d->Format('%Y'));
} else {
$t=mktime(0, 0, 0, (int)$d->Format('%n'), (int)$d->Format('%j'), (int)$d->Format('%Y'));
@@ -914,16 +755,192 @@ class WT_GedcomRecord {
// Get the last-change user for this record
//////////////////////////////////////////////////////////////////////////////
public function LastChangeUser() {
- $chan = $this->getChangeEvent();
+ $chan = $this->getFactByType('CHAN');
if (is_null($chan)) {
return '&nbsp;';
}
- $chan_user = $chan->getValue('_WT_USER');
+ $chan_user = $chan->getAttribute('_WT_USER');
if (empty($chan_user)) {
return '&nbsp;';
}
return $chan_user;
}
+
+ //////////////////////////////////////////////////////////////////////////////
+ // CRUD operations
+ //////////////////////////////////////////////////////////////////////////////
+
+ // Replace a (possibly empty) fact with a new (possibly empty) fact.
+ // This allows create/update/delete of individual facts
+ public function updateFact($fact_id, $gedcom, $update_chan) {
+ if (strpos("\r", $gedcom)!==false) {
+ // MSDOS line endings will break things in horrible ways
+ throw new Exception('Evil line endings found in WT_GedcomRecord::updateRecord(' . $gedcom . ')');
+ }
+ if ($this->pending==='') {
+ throw new Exception('Cannot edit a deleted record');
+ }
+ if ($gedcom && !preg_match('/^1 ' . WT_REGEX_TAG . '/', $gedcom)) {
+ throw new Exception('Invalid GEDCOM data passed to WT_GedcomRecord::updateFact()');
+ }
+
+ if ($this->pending) {
+ $old_gedcom = $this->pending;
+ } else {
+ $old_gedcom = $this->gedcom;
+ }
+
+ $new_gedcom = '0 @' . $this->getXref() . '@ ' . static::RECORD_TYPE;
+ $old_chan = $this->getFactByType('CHAN');
+ // Replacing (or deleting) an existing fact
+ foreach ($this->getFacts() as $fact) {
+ if ($fact->getFactId() == $fact_id) {
+ if ($gedcom) {
+ $new_gedcom .= "\n" . $gedcom;
+ }
+ } elseif ($fact->getTag()!='CHAN' || !$update_chan) {
+ $new_gedcom .= "\n" . $fact->getGedcom();
+ }
+ }
+ if ($update_chan) {
+ $new_gedcom .= "\n1 CHAN\n2 DATE " . date('d M Y') . "\n3 TIME " . date('H:i:s') . "\n2 _WT_USER " . WT_USER_NAME;
+ }
+
+ // Adding a new fact
+ if (!$fact_id) {
+ $new_gedcom .= "\n" . $gedcom;
+ }
+
+ if ($new_gedcom != $old_gedcom) {
+ // Save the changes
+ WT_DB::prepare(
+ "INSERT INTO `##change` (gedcom_id, xref, old_gedcom, new_gedcom, user_id) VALUES (?, ?, ?, ?, ?)"
+ )->execute(array(
+ $this->gedcom_id,
+ $this->xref,
+ $old_gedcom,
+ $new_gedcom,
+ WT_USER_ID
+ ));
+
+ // Clear the cache
+ self::$gedcom_record_cache = null;
+ self::$pending_record_cache = null;
+
+ if (get_user_setting(WT_USER_ID, 'auto_accept')) {
+ accept_all_changes($xref, $ged_id);
+ }
+ }
+ }
+
+ static public function createRecord($gedcom, $gedcom_id) {
+ if (preg_match('/^0 @(' . WT_REGEX_XREF . ')@ (' . WT_REGEX_TAG . ')/', $gedcom, $match)) {
+ $xref = $match[1];
+ $type = $match[2];
+ } else {
+ throw new Exception('Invalid argument to WT_GedcomRecord::createRecord(' . $gedcom . ')');
+ }
+ if (strpos("\r", $gedcom)!==false) {
+ // MSDOS line endings will break things in horrible ways
+ throw new Exception('Evil line endings found in WT_GedcomRecord::createRecord(' . $gedcom . ')');
+ }
+
+ // webtrees creates XREFs containing digits. Anything else (e.g. “new”) is just a placeholder.
+ if (!preg_match('/\d/', $xref)) {
+ $xref = get_new_xref($type);
+ $gedcom = preg_replace('/^0 @(' . WT_REGEX_XREF . ')@/', '0 @' . $xref . '@', $gedcom);
+ }
+
+ // Create a change record, if not already present
+ if (!preg_match('/\n1 CHAN/', $gedcom)) {
+ $gedcom .= "\n1 CHAN\n2 DATE " . date('d M Y') . "\n3 TIME " . date('H:i:s') . "\n2 _WT_USER " . WT_USER_NAME;
+ }
+
+ // Create a pending change
+ WT_DB::prepare(
+ "INSERT INTO `##change` (gedcom_id, xref, old_gedcom, new_gedcom, user_id) VALUES (?, ?, '', ?, ?)"
+ )->execute(array(
+ $gedcom_id,
+ $xref,
+ $gedcom,
+ $gedcom_id
+ ));
+
+ // Accept this pending change
+ if (get_user_setting(WT_USER_ID, 'auto_accept')) {
+ accept_all_changes($this->xref, $this->gedcom_id);
+ }
+
+ // Clear this record from the cache
+ self::$pending_record_cache = null;
+
+ AddToLog('Create: ' . $type . ' ' . $xref, 'edit');
+
+ // Return the newly created record
+ return WT_GedcomRecord::getInstance($xref);
+ }
+
+ private static function readRecord($xref, $gedcom_id) {
+ return WT_DB::prepare(static::SQL_FETCH)->execute(array($xref, $gedcom_id))->fetchOne();
+ }
+
+ public function updateRecord($gedcom, $update_chan) {
+ if (strpos("\r", $gedcom)!==false) {
+ // MSDOS line endings will break things in horrible ways
+ throw new Exception('Evil line endings found in WT_GedcomRecord::updateRecord(' . $gedcom . ')');
+ }
+
+ // Update the CHAN record
+ if ($update_chan) {
+ $gedcom = preg_replace('/\n1 CHAN(\n[2-9].*)*/', '', $gedcom);
+ $gedcom .= "\n1 CHAN\n2 DATE " . date('d M Y') . "\n3 TIME " . date('H:i:s') . "\n2 _WT_USER " . WT_USER_NAME;
+ }
+
+ // Create a pending change
+ WT_DB::prepare(
+ "INSERT INTO `##change` (gedcom_id, xref, old_gedcom, new_gedcom, user_id) VALUES (?, ?, ?, ?, ?)"
+ )->execute(array(
+ $this->gedcom_id,
+ $this->xref,
+ $this->getGedcom(),
+ $gedcom,
+ WT_USER_ID
+ ));
+
+ // Accept this pending change
+ if (get_user_setting(WT_USER_ID, 'auto_accept')) {
+ accept_all_changes($this->xref, $this->gedcom_id);
+ }
+
+ // Clear the cache
+ self::$gedcom_record_cache = null;
+ self::$pending_record_cache = null;
+
+ AddToLog('Update: ' . self::RECORD_TYPE . ' ' . $this->xref, 'edit');
+ }
+
+ public function deleteRecord() {
+ // Create a pending change
+ WT_DB::prepare(
+ "INSERT INTO `##change` (gedcom_id, xref, old_gedcom, new_gedcom, user_id) VALUES (?, ?, ?, '', ?)"
+ )->execute(array(
+ $this->gedcom_id,
+ $this->xref,
+ $this->getGedcom(),
+ WT_USER_ID
+ ));
+
+ // Accept this pending change
+ if (get_user_setting(WT_USER_ID, 'auto_accept')) {
+ accept_all_changes($this->xref, $this->gedcom_id);
+ }
+
+ // Clear the cache
+ self::$gedcom_record_cache = null;
+ self::$pending_record_cache = null;
+
+ AddToLog('Delete: ' . self::RECORD_TYPE . ' ' . $this->xref, 'edit');
+ }
}
diff --git a/library/WT/Person.php b/library/WT/Individual.php
index a2ab1229af..babefa9fbe 100644
--- a/library/WT/Person.php
+++ b/library/WT/Individual.php
@@ -1,5 +1,5 @@
<?php
-// Class file for a person
+// Class file for an individual
//
// webtrees: Web based Family History software
// Copyright (C) 2013 webtrees development team.
@@ -28,15 +28,11 @@ if (!defined('WT_WEBTREES')) {
exit;
}
-class WT_Person extends WT_GedcomRecord {
+class WT_Individual extends WT_GedcomRecord {
const RECORD_TYPE = 'INDI';
+ const SQL_FETCH = "SELECT i_gedcom FROM `##individuals` WHERE i_id=? AND i_file=?";
const URL_PREFIX = 'individual.php?pid=';
- var $indifacts = array();
- var $otherfacts = array();
- var $globalfacts = array();
- var $mediafacts = array();
- var $facts_parsed = false;
var $label = '';
var $highlightedimage = null;
var $file = '';
@@ -59,21 +55,21 @@ class WT_Person extends WT_GedcomRecord {
private $_getEstimatedDeathDate=null;
// Can the name of this record be shown?
- public function canDisplayName($access_level=WT_USER_ACCESS_LEVEL) {
+ public function canShowName($access_level=WT_USER_ACCESS_LEVEL) {
global $SHOW_LIVING_NAMES;
- return $SHOW_LIVING_NAMES>=$access_level || $this->canDisplayDetails($access_level);
+ return $SHOW_LIVING_NAMES>=$access_level || $this->canShow($access_level);
}
// Implement person-specific privacy logic
- protected function _canDisplayDetailsByType($access_level) {
+ protected function _canShowByType($access_level) {
global $SHOW_DEAD_PEOPLE, $KEEP_ALIVE_YEARS_BIRTH, $KEEP_ALIVE_YEARS_DEATH;
// Dead people...
if ($SHOW_DEAD_PEOPLE>=$access_level && $this->isDead()) {
$keep_alive=false;
if ($KEEP_ALIVE_YEARS_BIRTH) {
- preg_match_all('/\n1 (?:'.WT_EVENTS_BIRT.').*(?:\n[2-9].*)*(?:\n2 DATE (.+))/', $this->_gedrec, $matches, PREG_SET_ORDER);
+ preg_match_all('/\n1 (?:'.WT_EVENTS_BIRT.').*(?:\n[2-9].*)*(?:\n2 DATE (.+))/', $this->gedcom, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$date=new WT_Date($match[1]);
if ($date->isOK() && $date->gregorianYear()+$KEEP_ALIVE_YEARS_BIRTH > date('Y')) {
@@ -83,7 +79,7 @@ class WT_Person extends WT_GedcomRecord {
}
}
if ($KEEP_ALIVE_YEARS_DEATH) {
- preg_match_all('/\n1 (?:'.WT_EVENTS_DEAT.').*(?:\n[2-9].*)*(?:\n2 DATE (.+))/', $this->_gedrec, $matches, PREG_SET_ORDER);
+ preg_match_all('/\n1 (?:'.WT_EVENTS_DEAT.').*(?:\n[2-9].*)*(?:\n2 DATE (.+))/', $this->gedcom, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$date=new WT_Date($match[1]);
if ($date->isOK() && $date->gregorianYear()+$KEEP_ALIVE_YEARS_DEATH > date('Y')) {
@@ -97,8 +93,8 @@ class WT_Person extends WT_GedcomRecord {
}
}
// Consider relationship privacy (unless an admin is applying download restrictions)
- if (WT_USER_GEDCOM_ID && WT_USER_PATH_LENGTH && $this->getGedId()==WT_GED_ID && $access_level=WT_USER_ACCESS_LEVEL) {
- $self = WT_Person::getInstance(WT_USER_GEDCOM_ID);
+ if (WT_USER_GEDCOM_ID && WT_USER_PATH_LENGTH && $this->getGedcomId()==WT_GED_ID && $access_level=WT_USER_ACCESS_LEVEL) {
+ $self = WT_Individual::getInstance(WT_USER_GEDCOM_ID);
if ($self) {
return get_relationship($this, $self, true, WT_USER_PATH_LENGTH)!==false;
}
@@ -114,9 +110,9 @@ class WT_Person extends WT_GedcomRecord {
$rec='0 @'.$this->xref.'@ INDI';
if ($SHOW_LIVING_NAMES>=$access_level) {
// Show all the NAME tags, including subtags
- preg_match_all('/\n1 NAME.*(?:\n[2-9].*)*/', $this->_gedrec, $matches);
+ preg_match_all('/\n1 NAME.*(?:\n[2-9].*)*/', $this->gedcom, $matches);
foreach ($matches[0] as $match) {
- if (canDisplayFact($this->xref, $this->ged_id, $match, $access_level)) {
+ if (canDisplayFact($this->xref, $this->gedcom_id, $match, $access_level)) {
$rec.=$match;
}
}
@@ -124,31 +120,29 @@ class WT_Person extends WT_GedcomRecord {
$rec.="\n1 NAME ".WT_I18N::translate('Private');
}
// Just show the 1 FAMC/FAMS tag, not any subtags, which may contain private data
- preg_match_all('/\n1 (?:FAMC|FAMS) @('.WT_REGEX_XREF.')@/', $this->_gedrec, $matches, PREG_SET_ORDER);
+ preg_match_all('/\n1 (?:FAMC|FAMS) @('.WT_REGEX_XREF.')@/', $this->gedcom, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$rela=WT_Family::getInstance($match[1]);
- if ($rela && ($SHOW_PRIVATE_RELATIONSHIPS || $rela->canDisplayDetails($access_level))) {
+ if ($rela && ($SHOW_PRIVATE_RELATIONSHIPS || $rela->canShow($access_level))) {
$rec.=$match[0];
}
}
// Don't privatize sex.
- if (preg_match('/\n1 SEX [MFU]/', $this->_gedrec, $match)) {
+ if (preg_match('/\n1 SEX [MFU]/', $this->gedcom, $match)) {
$rec.=$match[0];
}
return $rec;
}
// Fetch the record from the database
- protected static function fetchGedcomRecord($xref, $ged_id) {
+ protected static function fetchGedcomRecord($xref, $gedcom_id) {
static $statement=null;
if ($statement===null) {
- $statement=WT_DB::prepare(
- "SELECT 'INDI' AS type, i_id AS xref, i_file AS ged_id, i_gedcom AS gedrec ".
- "FROM `##individuals` WHERE i_id=? AND i_file=?"
- );
+ $statement=WT_DB::prepare("SELECT i_gedcom FROM `##individuals` WHERE i_id=? AND i_file=?");
}
- return $statement->execute(array($xref, $ged_id))->fetchOneRow(PDO::FETCH_ASSOC);
+
+ return $statement->execute(array($xref, $gedcom_id))->fetchOne();
}
// Static helper function to sort an array of people by birth date
@@ -167,12 +161,12 @@ class WT_Person extends WT_GedcomRecord {
global $MAX_ALIVE_AGE;
// "1 DEAT Y" or "1 DEAT/2 DATE" or "1 DEAT/2 PLAC"
- if (preg_match('/\n1 (?:'.WT_EVENTS_DEAT.')(?: Y|(?:\n[2-9].+)*\n2 (DATE|PLAC) )/', $this->_gedrec)) {
+ if (preg_match('/\n1 (?:'.WT_EVENTS_DEAT.')(?: Y|(?:\n[2-9].+)*\n2 (DATE|PLAC) )/', $this->gedcom)) {
return true;
}
// If any event occured more than $MAX_ALIVE_AGE years ago, then assume the person is dead
- if (preg_match_all('/\n2 DATE (.+)/', $this->_gedrec, $date_matches)) {
+ if (preg_match_all('/\n2 DATE (.+)/', $this->gedcom, $date_matches)) {
foreach ($date_matches[1] as $date_match) {
$date=new WT_Date($date_match);
if ($date->isOK() && $date->MaxJD() <= WT_SERVER_JD - 365*$MAX_ALIVE_AGE) {
@@ -181,7 +175,7 @@ class WT_Person extends WT_GedcomRecord {
}
// The individual has one or more dated events. All are less than $MAX_ALIVE_AGE years ago.
// If one of these is a birth, the person must be alive.
- if (preg_match('/\n1 BIRT(?:\n[2-9].+)*\n2 DATE /', $this->_gedrec)) {
+ if (preg_match('/\n1 BIRT(?:\n[2-9].+)*\n2 DATE /', $this->gedcom)) {
return false;
}
}
@@ -192,7 +186,7 @@ class WT_Person extends WT_GedcomRecord {
foreach ($this->getChildFamilies(WT_PRIV_HIDE) as $family) {
foreach ($family->getSpouses(WT_PRIV_HIDE) as $parent) {
// Assume parents are no more than 45 years older than their children
- preg_match_all('/\n2 DATE (.+)/', $parent->_gedrec, $date_matches);
+ preg_match_all('/\n2 DATE (.+)/', $parent->gedcom, $date_matches);
foreach ($date_matches[1] as $date_match) {
$date=new WT_Date($date_match);
if ($date->isOK() && $date->MaxJD() <= WT_SERVER_JD - 365*($MAX_ALIVE_AGE+45)) {
@@ -204,7 +198,7 @@ class WT_Person extends WT_GedcomRecord {
// Check spouses
foreach ($this->getSpouseFamilies(WT_PRIV_HIDE) as $family) {
- preg_match_all('/\n2 DATE (.+)/', $family->_gedrec, $date_matches);
+ preg_match_all('/\n2 DATE (.+)/', $family->gedcom, $date_matches);
foreach ($date_matches[1] as $date_match) {
$date=new WT_Date($date_match);
// Assume marriage occurs after age of 10
@@ -215,7 +209,7 @@ class WT_Person extends WT_GedcomRecord {
// Check spouse dates
$spouse=$family->getSpouse($this, WT_PRIV_HIDE);
if ($spouse) {
- preg_match_all('/\n2 DATE (.+)/', $spouse->_gedrec, $date_matches);
+ preg_match_all('/\n2 DATE (.+)/', $spouse->gedcom, $date_matches);
foreach ($date_matches[1] as $date_match) {
$date=new WT_Date($date_match);
// Assume max age difference between spouses of 40 years
@@ -226,7 +220,7 @@ class WT_Person extends WT_GedcomRecord {
}
// Check child dates
foreach ($family->getChildren(WT_PRIV_HIDE) as $child) {
- preg_match_all('/\n2 DATE (.+)/', $child->_gedrec, $date_matches);
+ preg_match_all('/\n2 DATE (.+)/', $child->gedcom, $date_matches);
// Assume children born after age of 15
foreach ($date_matches[1] as $date_match) {
$date=new WT_Date($date_match);
@@ -237,7 +231,7 @@ class WT_Person extends WT_GedcomRecord {
// Check grandchildren
foreach ($child->getSpouseFamilies(WT_PRIV_HIDE) as $child_family) {
foreach ($child_family->getChildren(WT_PRIV_HIDE) as $grandchild) {
- preg_match_all('/\n2 DATE (.+)/', $grandchild->_gedrec, $date_matches);
+ preg_match_all('/\n2 DATE (.+)/', $grandchild->gedcom, $date_matches);
// Assume grandchildren born after age of 30
foreach ($date_matches[1] as $date_match) {
$date=new WT_Date($date_match);
@@ -265,10 +259,10 @@ class WT_Person extends WT_GedcomRecord {
$objectC = null;
// Iterate over all of the media items for the person
- preg_match_all('/\n(\d) OBJE @(' . WT_REGEX_XREF . ')@/', $this->getGedcomRecord(), $matches, PREG_SET_ORDER);
+ preg_match_all('/\n(\d) OBJE @(' . WT_REGEX_XREF . ')@/', $this->getGedcom(), $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$media = WT_Media::getInstance($match[2]);
- if (!$media || !$media->canDisplayDetails() || $media->isExternal()) {
+ if (!$media || !$media->canShow() || $media->isExternal()) {
continue;
}
$level = $match[1];
@@ -325,7 +319,7 @@ class WT_Person extends WT_GedcomRecord {
*/
function getBirthDate() {
if (is_null($this->_getBirthDate)) {
- if ($this->canDisplayDetails()) {
+ if ($this->canShow()) {
foreach ($this->getAllBirthDates() as $date) {
if ($date->isOK()) {
$this->_getBirthDate=$date;
@@ -348,7 +342,7 @@ class WT_Person extends WT_GedcomRecord {
*/
function getBirthPlace() {
if (is_null($this->_getBirthPlace)) {
- if ($this->canDisplayDetails()) {
+ if ($this->canShow()) {
foreach ($this->getAllBirthPlaces() as $place) {
if ($place) {
$this->_getBirthPlace=$place;
@@ -371,7 +365,7 @@ class WT_Person extends WT_GedcomRecord {
*/
function getCensBirthPlace() {
if (is_null($this->_getBirthPlace)) {
- if ($this->canDisplayDetails()) {
+ if ($this->canShow()) {
foreach ($this->getAllBirthPlaces() as $place) {
if ($place) {
$this->_getBirthPlace=$place;
@@ -408,7 +402,7 @@ class WT_Person extends WT_GedcomRecord {
*/
function getDeathDate($estimate = true) {
if (is_null($this->_getDeathDate)) {
- if ($this->canDisplayDetails()) {
+ if ($this->canShow()) {
foreach ($this->getAllDeathDates() as $date) {
if ($date->isOK()) {
$this->_getDeathDate=$date;
@@ -431,7 +425,7 @@ class WT_Person extends WT_GedcomRecord {
*/
function getDeathPlace() {
if (is_null($this->_getDeathPlace)) {
- if ($this->canDisplayDetails()) {
+ if ($this->canShow()) {
foreach ($this->getAllDeathPlaces() as $place) {
if ($place) {
$this->_getDeathPlace=$place;
@@ -498,7 +492,7 @@ class WT_Person extends WT_GedcomRecord {
// Get all the dates/places for births/deaths - for the INDI lists
function getAllBirthDates() {
if (is_null($this->_getAllBirthDates)) {
- if ($this->canDisplayDetails()) {
+ if ($this->canShow()) {
foreach (explode('|', WT_EVENTS_BIRT) as $event) {
if ($this->_getAllBirthDates=$this->getAllEventDates($event)) {
break;
@@ -512,7 +506,7 @@ class WT_Person extends WT_GedcomRecord {
}
function getAllBirthPlaces() {
if (is_null($this->_getAllBirthPlaces)) {
- if ($this->canDisplayDetails()) {
+ if ($this->canShow()) {
foreach (explode('|', WT_EVENTS_BIRT) as $event) {
if ($this->_getAllBirthPlaces=$this->getAllEventPlaces($event)) {
break;
@@ -526,7 +520,7 @@ class WT_Person extends WT_GedcomRecord {
}
function getAllDeathDates() {
if (is_null($this->_getAllDeathDates)) {
- if ($this->canDisplayDetails()) {
+ if ($this->canShow()) {
foreach (explode('|', WT_EVENTS_DEAT) as $event) {
if ($this->_getAllDeathDates=$this->getAllEventDates($event)) {
break;
@@ -540,7 +534,7 @@ class WT_Person extends WT_GedcomRecord {
}
function getAllDeathPlaces() {
if (is_null($this->_getAllDeathPlaces)) {
- if ($this->canDisplayDetails()) {
+ if ($this->canShow()) {
foreach (explode('|', WT_EVENTS_DEAT) as $event) {
if ($this->_getAllDeathPlaces=$this->getAllEventPlaces($event)) {
break;
@@ -664,7 +658,7 @@ class WT_Person extends WT_GedcomRecord {
// the privatize-gedcom function, and we are allowed to know this.
function getSex() {
if (is_null($this->sex)) {
- if (preg_match('/\n1 SEX ([MF])/', $this->_gedrec, $match)) {
+ if (preg_match('/\n1 SEX ([MF])/', $this->gedcom, $match)) {
$this->sex=$match[1];
} else {
$this->sex='U';
@@ -753,7 +747,7 @@ class WT_Person extends WT_GedcomRecord {
if ($access_level==WT_PRIV_HIDE) {
// special case, (temporary - cannot make this generic as other code depends on the private cached values)
$families=array();
- preg_match_all('/\n1 FAMS @('.WT_REGEX_XREF.')@/', $this->_gedrec, $match);
+ preg_match_all('/\n1 FAMS @('.WT_REGEX_XREF.')@/', $this->gedcom, $match);
foreach ($match[1] as $pid) {
$family=WT_Family::getInstance($pid);
if ($family) {
@@ -765,10 +759,10 @@ class WT_Person extends WT_GedcomRecord {
if ($this->_spouseFamilies===null) {
$this->_spouseFamilies=array();
- preg_match_all('/\n1 FAMS @('.WT_REGEX_XREF.')@/', $this->_gedrec, $match);
+ preg_match_all('/\n1 FAMS @('.WT_REGEX_XREF.')@/', $this->gedcom, $match);
foreach ($match[1] as $pid) {
$family=WT_Family::getInstance($pid);
- if ($family && ($SHOW_PRIVATE_RELATIONSHIPS || $family->canDisplayDetails($access_level))) {
+ if ($family && ($SHOW_PRIVATE_RELATIONSHIPS || $family->canShow($access_level))) {
$this->_spouseFamilies[]=$family;
}
}
@@ -794,7 +788,7 @@ class WT_Person extends WT_GedcomRecord {
// Get a count of the children for this individual
function getNumberOfChildren() {
- if (preg_match('/\n1 NCHI (\d+)(?:\n|$)/', $this->getGedcomRecord(), $match)) {
+ if (preg_match('/\n1 NCHI (\d+)(?:\n|$)/', $this->getGedcom(), $match)) {
return $match[1];
} else {
$children=array();
@@ -814,7 +808,7 @@ class WT_Person extends WT_GedcomRecord {
if ($access_level==WT_PRIV_HIDE) {
// special case, (temporary - cannot make this generic as other code depends on the private cached values)
$families=array();
- preg_match_all('/\n1 FAMC @('.WT_REGEX_XREF.')@/', $this->_gedrec, $match);
+ preg_match_all('/\n1 FAMC @('.WT_REGEX_XREF.')@/', $this->gedcom, $match);
foreach ($match[1] as $pid) {
$family=WT_Family::getInstance($pid);
if ($family) {
@@ -826,10 +820,10 @@ class WT_Person extends WT_GedcomRecord {
if ($this->_childFamilies===null) {
$this->_childFamilies=array();
- preg_match_all('/\n1 FAMC @('.WT_REGEX_XREF.')@/', $this->_gedrec, $match);
+ preg_match_all('/\n1 FAMC @('.WT_REGEX_XREF.')@/', $this->gedcom, $match);
foreach ($match[1] as $pid) {
$family=WT_Family::getInstance($pid);
- if ($family && ($SHOW_PRIVATE_RELATIONSHIPS || $family->canDisplayDetails($access_level))) {
+ if ($family && ($SHOW_PRIVATE_RELATIONSHIPS || $family->canShow($access_level))) {
$this->_childFamilies[]=$family;
}
}
@@ -852,19 +846,19 @@ class WT_Person extends WT_GedcomRecord {
// If there is more than one FAMC record, choose the preferred parents:
// a) records with '2 _PRIMARY'
foreach ($families as $famid=>$fam) {
- if (preg_match("/\n1 FAMC @{$famid}@\n(?:[2-9].*\n)*(?:2 _PRIMARY Y)/", $this->getGedcomRecord())) {
+ if (preg_match("/\n1 FAMC @{$famid}@\n(?:[2-9].*\n)*(?:2 _PRIMARY Y)/", $this->getGedcom())) {
return $fam;
}
}
// b) records with '2 PEDI birt'
foreach ($families as $famid=>$fam) {
- if (preg_match("/\n1 FAMC @{$famid}@\n(?:[2-9].*\n)*(?:2 PEDI birth)/", $this->getGedcomRecord())) {
+ if (preg_match("/\n1 FAMC @{$famid}@\n(?:[2-9].*\n)*(?:2 PEDI birth)/", $this->getGedcom())) {
return $fam;
}
}
// c) records with no '2 PEDI'
foreach ($families as $famid=>$fam) {
- if (!preg_match("/\n1 FAMC @{$famid}@\n(?:[2-9].*\n)*(?:2 PEDI)/", $this->getGedcomRecord())) {
+ if (!preg_match("/\n1 FAMC @{$famid}@\n(?:[2-9].*\n)*(?:2 PEDI)/", $this->getGedcom())) {
return $fam;
}
}
@@ -877,7 +871,7 @@ class WT_Person extends WT_GedcomRecord {
* @return string FAMC:PEDI value [ adopted | birth | foster | sealing ]
*/
function getChildFamilyPedigree($famid) {
- $subrec = get_sub_record(1, '1 FAMC @'.$famid.'@', $this->getGedcomRecord());
+ $subrec = get_sub_record(1, '1 FAMC @'.$famid.'@', $this->getGedcom());
$pedi = get_gedcom_value('PEDI', 2, $subrec);
// birth=default => return an empty string
return ($pedi=='birth') ? '' : $pedi;
@@ -925,35 +919,9 @@ class WT_Person extends WT_GedcomRecord {
return $step_families;
}
- /**
- * get global facts
- * @return array
- */
- function getGlobalFacts() {
- $this->parseFacts();
- return $this->globalfacts;
- }
- /**
- * get indi facts
- * @return array
- */
- function getIndiFacts() {
- $this->parseFacts();
- return $this->indifacts;
- }
-
- /**
- * get other facts
- * @return array
- */
- function getOtherFacts() {
- $this->parseFacts();
- return $this->otherfacts;
- }
-
// A label for a parental family group
function getChildFamilyLabel(WT_Family $family) {
- if (preg_match('/\n1 FAMC @'.$family->getXref().'@(?:\n[2-9].*)*\n2 PEDI (.+)/', $this->getGedcomRecord(), $match)) {
+ if (preg_match('/\n1 FAMC @'.$family->getXref().'@(?:\n[2-9].*)*\n2 PEDI (.+)/', $this->getGedcom(), $match)) {
// A specified pedigree
return WT_Gedcom_Code_Pedi::getChildFamilyLabel($match[1]);
} else {
@@ -1001,8 +969,9 @@ class WT_Person extends WT_GedcomRecord {
}
}
// It should not be possible to get here
- throw new Exception('Invalid family in WT_Person::getStepFamilyLabel(' . $family . ')');
+ throw new Exception('Invalid family in WT_Individual::getStepFamilyLabel(' . $family . ')');
}
+
/**
* get the correct label for a family
* @param Family $family the family to get the label for
@@ -1025,595 +994,6 @@ class WT_Person extends WT_GedcomRecord {
// I18N: %s is the spouse name
return WT_I18N::translate('Family with %s', $spouse);
}
- /**
- * get updated Person
- * If there is an updated individual record in the gedcom file
- * return a new person object for it
- * @return Person
- */
- function getUpdatedPerson() {
- if ($this->getChanged()) {
- return null;
- }
- if (WT_USER_CAN_EDIT && $this->canDisplayDetails()) {
- $newrec = find_updated_record($this->xref, $this->ged_id);
- if (!is_null($newrec)) {
- $new = new WT_Person($newrec);
- $new->setChanged(true);
- return $new;
- }
- }
- return null;
- }
- /**
- * Parse the facts from the individual record
- */
- function parseFacts() {
- parent::parseFacts();
- //-- only run this function once
- if ($this->facts_parsed) return;
- //-- don't run this function if privacy does not allow viewing of details
- if (!$this->canDisplayDetails()) return;
- $sexfound = false;
- //-- run the parseFacts() method from the parent class
- $this->facts_parsed = true;
-
- //-- sort the fact info into different categories for people
- foreach ($this->facts as $f=>$event) {
- $fact = $event->getTag();
- if ($fact=='NAME') {
- // -- handle special name fact case
- $this->globalfacts[] = $event;
- } elseif ($fact=='SOUR') {
- // -- handle special source fact case
- $this->otherfacts[] = $event;
- } elseif ($fact=='NOTE') {
- // -- handle special note fact case
- $this->otherfacts[] = $event;
- } elseif ($fact=='SEX') {
- // -- handle special sex case
- $this->globalfacts[] = $event;
- $sexfound = true;
- } elseif ($fact=='OBJE') {
- } else {
- $this->indifacts[] = $event;
- }
- }
- //-- add a new sex fact if one was not found
- if (!$sexfound) {
- $this->globalfacts[] = new WT_Event('1 SEX U', $this, 'new');
- }
- }
- /**
- * add facts from the family record
- * @param boolean $otherfacts whether or not to add other related facts such as parents facts, associated people facts, and historical facts
- */
- function add_family_facts($otherfacts = true) {
- global $GEDCOM, $nonfacts, $nonfamfacts;
-
- if (!isset($nonfacts)) $nonfacts = array();
- if (!isset($nonfamfacts)) $nonfamfacts = array();
-
- if (!$this->canDisplayDetails()) return;
- $this->parseFacts();
- //-- Get the facts from the family with spouse (FAMS)
- foreach ($this->getSpouseFamilies() as $family) {
- $updfamily = $family->getUpdatedFamily(); //-- updated family ?
- $spouse = $family->getSpouse($this);
-
- if ($updfamily) {
- $family->diffMerge($updfamily);
- }
- $facts = $family->getFacts();
- $hasdiv = false;
- /* @var $event WT_Event */
- foreach ($facts as $event) {
- $fact = $event->getTag();
- if ($fact=='DIV') $hasdiv = true;
- // -- handle special source fact case
- if ($fact!='SOUR' && $fact!='NOTE' && $fact!='CHAN' && $fact!='_UID' && $fact!='RIN') {
- if (!in_array($fact, $nonfacts) && !in_array($fact, $nonfamfacts)) {
- $event->setSpouse($spouse);
- if ($fact!='OBJE') {
- $this->indifacts[]=$event;
- } else {
- $this->otherfacts[]=$event;
- }
- }
- }
- }
- if ($otherfacts) {
- if (!$hasdiv && !is_null($spouse)) $this->add_spouse_facts($spouse, $family->getGedcomRecord());
- $this->add_children_facts($family, '_CHIL', '');
- }
- }
- if ($otherfacts) {
- $this->add_parents_facts($this, 1);
- $this->add_historical_facts();
- $this->add_asso_facts();
- }
- }
-
- // Add parents' (and parents' relatives') events to individual facts array
- function add_parents_facts($person, $sosa) {
- global $SHOW_RELATIVES_EVENTS;
-
- switch ($sosa) {
- case 1:
- foreach ($person->getChildFamilies() as $family) {
- // Add siblings
- $this->add_children_facts($family, '_SIBL', '');
- foreach ($family->getSpouses() as $spouse) {
- foreach ($spouse->getSpouseFamilies() as $sfamily) {
- if (!$family->equals($sfamily)) {
- // Add half-siblings
- $this->add_children_facts($sfamily, '_HSIB', 'par');
- }
- }
- // Add grandparents
- $this->add_parents_facts($spouse, $spouse->getSex()=='F' ? 3 : 2);
- }
- }
-
- $rela='';
- break;
- case 2:
- $rela='fat';
- break;
- case 3:
- $rela='mot';
- break;
- }
-
- // Only include events between birth and death
- $bDate=$this->getEstimatedBirthDate();
- $dDate=$this->getEstimatedDeathDate();
-
- foreach ($person->getChildFamilies() as $famid=>$family) {
- foreach ($family->getSpouses() as $parent) {
- if (strstr($SHOW_RELATIVES_EVENTS, '_DEAT'.($sosa==1 ? '_PARE' : '_GPAR'))) {
- foreach ($parent->getAllFactsByType(explode('|', WT_EVENTS_DEAT)) as $sEvent) {
- if ($sEvent->getDate()->isOK() && WT_Date::Compare($bDate, $sEvent->getDate())<=0 && WT_Date::Compare($sEvent->getDate(), $dDate)<=0) {
- switch ($sosa) {
- case 1:
- // Convert the event to a close relatives event
- $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_DEAT.')/', '1 _$1_PARE ', $sEvent->getGedcomRecord()); // Full
- $tmp_rec="1 _".$sEvent->getTag()."_PARE\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated
- break;
- case 2:
- // Convert the event to a close relatives event
- $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_DEAT.')/', '1 _$1_GPA1 ', $sEvent->getGedcomRecord()); // Full
- $tmp_rec="1 _".$sEvent->getTag()."_GPA1\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated
- break;
- case 3:
- // Convert the event to a close relatives event
- $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_DEAT.')/', '1 _$1_GPA2 ', $sEvent->getGedcomRecord()); // Full
- $tmp_rec="1 _".$sEvent->getTag()."_GPA2\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated
- break;
- }
- // Create a new event
- $this->indifacts[]=new WT_Event($tmp_rec."\n2 _ASSO @".$parent->getXref()."@", $parent, 0);
- }
- }
- }
- }
-
- if ($sosa==1 && strstr($SHOW_RELATIVES_EVENTS, '_MARR_PARE')) {
- // add father/mother marriages
- foreach ($family->getSpouses() as $parent) {
- foreach ($parent->getSpouseFamilies() as $sfamily) {
- foreach ($sfamily->getAllFactsByType(explode('|', WT_EVENTS_MARR)) as $sEvent) {
- if ($sEvent->getDate()->isOK() && WT_Date::Compare($bDate, $sEvent->getDate())<=0 && WT_Date::Compare($sEvent->getDate(), $dDate)<=0) {
- if ($sfamily->equals($family)) {
- if ($parent->getSex()=='F') {
- // show current family marriage only once
- continue;
- }
- // marriage of parents (to each other)
- // Convert the event to a close relatives event
- $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_MARR.')/', '1 _$1_FAMC ', $sEvent->getGedcomRecord()); // Full
- $tmp_rec="1 _".$sEvent->getTag()."_FAMC\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated
- } else {
- // marriage of a parent (to another spouse)
- // Convert the event to a close relatives event
- $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_MARR.')/', '1 _$1_PARE ', $sEvent->getGedcomRecord()); // Full
- $tmp_rec="1 _".$sEvent->getTag()."_PARE\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated
- }
- // Add links to both spouses
- foreach ($sfamily->getSpouses() as $spouse) {
- $tmp_rec .= "\n2 _ASSO @" . $spouse->getXref() . '@';
- }
- // Create a new event
- $tmp = new WT_Event($tmp_rec, $sfamily, 0);
- if (!$sfamily->equals($family)) {
- $tmp->setSpouse($parent);
- }
- $this->indifacts[]=$tmp;
- }
- }
- }
- }
- }
- }
- }
-
- /**
- * add children events to individual facts array
- *
- * @param string $family Family object
- * @param string $option Family level indicator
- * @param string $relation Relationship path indicator
- * @return records added to indifacts array
- */
- function add_children_facts($family, $option, $relation) {
- global $SHOW_RELATIVES_EVENTS;
-
- // Deal with recursion.
- switch ($option) {
- case '_CHIL':
- // Add grandchildren
- foreach ($family->getChildren() as $child) {
- foreach ($child->getSpouseFamilies() as $cfamily) {
- switch ($child->getSex()) {
- case 'M':
- $this->add_children_facts($cfamily, '_GCHI', 'son');
- break;
- case 'F':
- $this->add_children_facts($cfamily, '_GCHI', 'dau');
- break;
- case 'U':
- $this->add_children_facts($cfamily, '_GCHI', 'chi');
- break;
- }
- }
- }
- break;
- }
-
- // For each child in the family
- foreach ($family->getChildren() as $child) {
- if ($child->getXref()==$this->getXref()) {
- // We are not our own sibling!
- continue;
- }
- // add child's birth
- if (strpos($SHOW_RELATIVES_EVENTS, '_BIRT'.str_replace('_HSIB', '_SIBL', $option))!==false) {
- foreach ($child->getAllFactsByType(explode('|', WT_EVENTS_BIRT)) as $sEvent) {
- $sgdate=$sEvent->getDate();
- // Always show _BIRT_CHIL, even if the dates are not known
- if ($option=='_CHIL' || $sgdate->isOK() && WT_Date::Compare($this->getEstimatedBirthDate(), $sgdate)<=0 && WT_Date::Compare($sgdate, $this->getEstimatedDeathDate())<=0) {
- if ($option=='_GCHI' && $relation=='dau') {
- // Convert the event to a close relatives event.
- $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_BIRT.')/', '1 _$1_GCH1', $sEvent->getGedcomRecord()); // Full
- $tmp_rec="1 _".$sEvent->getTag()."_GCH1\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated
- } elseif ($option=='_GCHI' && $relation=='son') {
- // Convert the event to a close relatives event.
- $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_BIRT.')/', '1 _$1_GCH2', $sEvent->getGedcomRecord()); // Full
- $tmp_rec="1 _".$sEvent->getTag()."_GCH2\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated
- } else {
- // Convert the event to a close relatives event.
- $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_BIRT.')/', '1 _$1'.$option, $sEvent->getGedcomRecord()); // Full
- $tmp_rec="1 _".$sEvent->getTag().$option."\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated
- }
- $event=new WT_Event($tmp_rec."\n2 _ASSO @".$child->getXref()."@", $child, 0);
- if (!in_array($event, $this->indifacts)) {
- $this->indifacts[]=$event;
- }
- }
- }
- }
- // add child's death
- if (strpos($SHOW_RELATIVES_EVENTS, '_DEAT'.str_replace('_HSIB', '_SIBL', $option))!==false) {
- foreach ($child->getAllFactsByType(explode('|', WT_EVENTS_DEAT)) as $sEvent) {
- $sgdate=$sEvent->getDate();
- $srec = $sEvent->getGedcomRecord();
- if ($sgdate->isOK() && WT_Date::Compare($this->getEstimatedBirthDate(), $sgdate)<=0 && WT_Date::Compare($sgdate, $this->getEstimatedDeathDate())<=0) {
- if ($option=='_GCHI' && $relation=='dau') {
- // Convert the event to a close relatives event.
- $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_DEAT.')/', '1 _$1_GCH1', $sEvent->getGedcomRecord()); // Full
- $tmp_rec="1 _".$sEvent->getTag()."_GCH1\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated
- } elseif ($option=='_GCHI' && $relation=='son') {
- // Convert the event to a close relatives event.
- $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_DEAT.')/', '1 _$1_GCH2', $sEvent->getGedcomRecord()); // Full
- $tmp_rec="1 _".$sEvent->getTag()."_GCH2\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated
- } else {
- // Convert the event to a close relatives event.
- $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_DEAT.')/', '1 _$1'.$option, $sEvent->getGedcomRecord()); // Full
- $tmp_rec="1 _".$sEvent->getTag().$option."\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated
- }
- $event=new WT_Event($tmp_rec."\n2 _ASSO @".$child->getXref()."@", $child, 0);
- if (!in_array($event, $this->indifacts)) {
- $this->indifacts[]=$event;
- }
- }
- }
- }
- // add child's marriage
- if (strstr($SHOW_RELATIVES_EVENTS, '_MARR'.str_replace('_HSIB', '_SIBL', $option))) {
- foreach ($child->getSpouseFamilies() as $sfamily) {
- foreach ($sfamily->getAllFactsByType(explode('|', WT_EVENTS_MARR)) as $sEvent) {
- $sgdate=$sEvent->getDate();
- if ($sgdate->isOK() && WT_Date::Compare($this->getEstimatedBirthDate(), $sgdate)<=0 && WT_Date::Compare($sgdate, $this->getEstimatedDeathDate())<=0) {
- if ($option=='_GCHI' && $relation=='dau') {
- // Convert the event to a close relatives event.
- $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_MARR.')/', '1 _$1_GCH1', $sEvent->getGedcomRecord());
- $tmp_rec="1 _".$sEvent->getTag()."_GCH1\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated
- } elseif ($option=='_GCHI' && $relation=='son') {
- // Convert the event to a close relatives event.
- $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_MARR.')/', '1 _$1_GCH2', $sEvent->getGedcomRecord());
- $tmp_rec="1 _".$sEvent->getTag()."_GCH2\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated
- } else {
- // Convert the event to a close relatives event.
- $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_MARR.')/', '1 _$1'.$option, $sEvent->getGedcomRecord());
- $tmp_rec="1 _".$sEvent->getTag().$option."\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated
- }
- // Add links to both spouses
- foreach ($sfamily->getSpouses() as $spouse) {
- $tmp_rec .= "\n2 _ASSO @" . $spouse->getXref() . '@';
- }
- // Create a new event
- $tmp = new WT_Event($tmp_rec, $sfamily, 0);
- $tmp->setSpouse($child);
- $this->indifacts[]=$tmp;
- }
- }
- }
- }
- }
- }
- /**
- * add spouse events to individual facts array
- *
- * bdate = indi birth date record
- * ddate = indi death date record
- *
- * @param string $spouse Person object
- * @param string $famrec family Gedcom record
- * @return records added to indifacts array
- */
- function add_spouse_facts($spouse, $famrec='') {
- global $SHOW_RELATIVES_EVENTS;
-
- // do not show if divorced
- if (preg_match('/\n1 (?:'.WT_EVENTS_DIV.')\b/', $famrec)) {
- return;
- }
- // Only include events between birth and death
- $bDate=$this->getEstimatedBirthDate();
- $dDate=$this->getEstimatedDeathDate();
-
- // add spouse death
- if ($spouse && strstr($SHOW_RELATIVES_EVENTS, '_DEAT_SPOU')) {
- foreach ($spouse->getAllFactsByType(explode('|', WT_EVENTS_DEAT)) as $sEvent) {
- $sdate=$sEvent->getDate();
- if ($sdate->isOK() && WT_Date::Compare($this->getEstimatedBirthDate(), $sdate)<=0 && WT_Date::Compare($sdate, $this->getEstimatedDeathDate())<=0) {
- // Convert the event to a close relatives event.
- $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_DEAT.')/', '1 _$1_SPOU ', $sEvent->getGedcomRecord()); // Full
- $tmp_rec="1 _".$sEvent->getTag()."_SPOU\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated
- // Create a new event
- $this->indifacts[]=new WT_Event($tmp_rec."\n2 _ASSO @".$spouse->getXref()."@", $spouse, 0);
- }
- }
- }
- }
-
- /**
- * add historical events to individual facts array
- *
- * @return records added to indifacts array
- *
- * Historical facts are imported from optional language file : histo.xx.php
- * where xx is language code
- * This file should contain records similar to :
- *
- * $histo[]="1 EVEN\n2 TYPE History\n2 DATE 11 NOV 1918\n2 NOTE WW1 Armistice";
- * $histo[]="1 EVEN\n2 TYPE History\n2 DATE 8 MAY 1945\n2 NOTE WW2 Armistice";
- * etc...
- *
- */
- function add_historical_facts() {
- global $SHOW_RELATIVES_EVENTS;
- if (!$SHOW_RELATIVES_EVENTS) return;
-
- // Only include events between birth and death
- $bDate=$this->getEstimatedBirthDate();
- $dDate=$this->getEstimatedDeathDate();
- if (!$bDate->isOK()) return;
-
- if (file_exists(WT_Site::preference('INDEX_DIRECTORY').'histo.'.WT_LOCALE.'.php')) {
- require WT_Site::preference('INDEX_DIRECTORY').'histo.'.WT_LOCALE.'.php';
- foreach ($histo as $indexval=>$hrec) {
- $sdate=new WT_Date(get_gedcom_value('DATE', 2, $hrec));
- if ($sdate->isOK() && WT_Date::Compare($this->getEstimatedBirthDate(), $sdate)<=0 && WT_Date::Compare($sdate, $this->getEstimatedDeathDate())<=0) {
- $event = new WT_Event($hrec, null, -1);
- $this->indifacts[] = $event;
- }
- }
- }
- }
- /**
- * add events where pid is an ASSOciate
- *
- * @return records added to indifacts array
- *
- */
- function add_asso_facts() {
- $associates=array_merge(
- fetch_linked_indi($this->getXref(), 'ASSO', $this->ged_id),
- fetch_linked_indi($this->getXref(), '_ASSO', $this->ged_id),
- fetch_linked_fam ($this->getXref(), 'ASSO', $this->ged_id),
- fetch_linked_fam ($this->getXref(), '_ASSO', $this->ged_id)
- );
- foreach ($associates as $associate) {
- foreach ($associate->getFacts() as $event) {
- $srec = $event->getGedcomRecord();
- foreach (array('ASSO', '_ASSO') as $asso_tag) {
- $arec = get_sub_record(2, '2 ' . $asso_tag . ' @' . $this->getXref() . '@', $srec);
- if ($arec) {
- // Extract the important details from the fact
- $factrec='1 '.$event->getTag();
- if (preg_match('/\n2 DATE .*/', $srec, $match)) {
- $factrec.=$match[0];
- }
- if (preg_match('/\n2 PLAC .*/', $srec, $match)) {
- $factrec.=$match[0];
- }
- if ($associate instanceof WT_Family) {
- foreach ($associate->getSpouses() as $spouse) {
- $factrec.="\n2 $asso_tag @".$spouse->getXref().'@';
- }
- } else {
- $factrec.="\n2 $asso_tag @".$associate->getXref().'@';
- // CHR/BAPM events are commonly used. Generate the reverse relationship
- if (preg_match('/^(?:BAPM|CHR)$/', $event->getTag()) && preg_match('/3 RELA god(?:parent|mother|father)/', $event->getGedcomRecord())) {
- switch ($associate->getSex()) {
- case 'M':
- $factrec.="\n3 RELA godson";
- break;
- case 'F':
- $factrec.="\n3 RELA goddaughter";
- break;
- case 'U':
- $factrec.="\n3 RELA godchild";
- break;
- }
- }
- }
- $this->indifacts[] = new WT_Event($factrec, $associate, 0);
- }
- }
- }
- }
- }
-
- /**
- * Merge the facts from another Person object into this object
- * for generating a diff view
- * @param Person $diff the person to compare facts with
- */
- function diffMerge($diff) {
- if (is_null($diff)) return;
- $this->parseFacts();
- $diff->parseFacts();
- //-- loop through new facts and add them to the list if they are any changes
- //-- compare new and old facts of the Personal Fact and Details tab 1
- for ($i=0; $i<count($this->indifacts); $i++) {
- $found=false;
- $oldfactrec = $this->indifacts[$i]->getGedcomRecord();
- foreach ($diff->indifacts as $newfact) {
- $newfactrec = $newfact->getGedcomRecord();
- //-- remove all whitespace for comparison
- $tnf = preg_replace('/\s+/', ' ', $newfactrec);
- $tif = preg_replace('/\s+/', ' ', $oldfactrec);
- if ($tnf==$tif) {
- $this->indifacts[$i] = $newfact; //-- make sure the correct linenumber is used
- $found=true;
- break;
- }
- }
- //-- fact was deleted?
- if (!$found) {
- $this->indifacts[$i]->setIsOld();
- }
- }
- //-- check for any new facts being added
- foreach ($diff->indifacts as $newfact) {
- $found=false;
- foreach ($this->indifacts as $fact) {
- $tif = preg_replace('/\s+/', ' ', $fact->getGedcomRecord());
- $tnf = preg_replace('/\s+/', ' ', $newfact->getGedcomRecord());
- if ($tif==$tnf) {
- $found=true;
- break;
- }
- }
- if (!$found) {
- $newfact->setIsNew();
- $this->indifacts[]=$newfact;
- }
- }
- //-- compare new and old facts of the Notes Sources and Media tab 2
- for ($i=0; $i<count($this->otherfacts); $i++) {
- $found=false;
- foreach ($diff->otherfacts as $newfact) {
- if (trim($newfact->getGedcomRecord())==trim($this->otherfacts[$i]->getGedcomRecord())) {
- $this->otherfacts[$i] = $newfact; //-- make sure the correct linenumber is used
- $found=true;
- break;
- }
- }
- if (!$found) {
- $this->otherfacts[$i]->setIsOld();
- }
- }
- foreach ($diff->otherfacts as $indexval => $newfact) {
- $found=false;
- foreach ($this->otherfacts as $indexval => $fact) {
- if (trim($fact->getGedcomRecord())==trim($newfact->getGedcomRecord())) {
- $found=true;
- break;
- }
- }
- if (!$found) {
- $newfact->setIsNew();
- $this->otherfacts[]=$newfact;
- }
- }
-
- //-- compare new and old facts of the Global facts
- for ($i=0; $i<count($this->globalfacts); $i++) {
- $found=false;
- foreach ($diff->globalfacts as $indexval => $newfact) {
- if (trim($newfact->getGedcomRecord())==trim($this->globalfacts[$i]->getGedcomRecord())) {
- $this->globalfacts[$i] = $newfact; //-- make sure the correct linenumber is used
- $found=true;
- break;
- }
- }
- if (!$found) {
- $this->globalfacts[$i]->setIsOld();
- }
- }
- foreach ($diff->globalfacts as $indexval => $newfact) {
- $found=false;
- foreach ($this->globalfacts as $indexval => $fact) {
- if (trim($fact->getGedcomRecord())==trim($newfact->getGedcomRecord())) {
- $found=true;
- break;
- }
- }
- if (!$found) {
- $newfact->setIsNew();
- $this->globalfacts[]=$newfact;
- }
- }
-
- foreach ($diff->getChildFamilies() as $diff_family) {
- $exists=false;
- foreach ($this->getChildFamilies() as $family) {
- if ($family->equals($diff_family)) {
- $exists=true;
- break;
- }
- }
- if (!$exists) {
- $this->_childFamilies[]=$diff_family;
- }
- }
-
- foreach ($diff->getSpouseFamilies() as $diff_family) {
- $exists=false;
- foreach ($this->getSpouseFamilies() as $family) {
- if ($family->equals($diff_family)) {
- $exists=true;
- break;
- }
- }
- if (!$exists) {
- $this->_spouseFamilies[]=$diff_family;
- }
- }
- }
/**
* get primary parents names for this person
@@ -1677,19 +1057,19 @@ class WT_Person extends WT_GedcomRecord {
// 1 NAME Carlos /Vasquez y Sante/
// 2 GIVN Carlos
// 2 SURN Vasquez,Sante
- protected function _addName($type, $full, $gedrec) {
+ protected function _addName($type, $full, $gedcom) {
global $UNKNOWN_NN, $UNKNOWN_PN;
////////////////////////////////////////////////////////////////////////////
// Extract the structured name parts - use for "sortable" names and indexes
////////////////////////////////////////////////////////////////////////////
- $sublevel=1+(int)$gedrec[0];
- $NPFX=preg_match("/\n{$sublevel} NPFX (.+)/", $gedrec, $match) ? $match[1] : '';
- $GIVN=preg_match("/\n{$sublevel} GIVN (.+)/", $gedrec, $match) ? $match[1] : '';
- $SURN=preg_match("/\n{$sublevel} SURN (.+)/", $gedrec, $match) ? $match[1] : '';
- $NSFX=preg_match("/\n{$sublevel} NSFX (.+)/", $gedrec, $match) ? $match[1] : '';
- $NICK=preg_match("/\n{$sublevel} NICK (.+)/", $gedrec, $match) ? $match[1] : '';
+ $sublevel=1+(int)$gedcom[0];
+ $NPFX=preg_match("/\n{$sublevel} NPFX (.+)/", $gedcom, $match) ? $match[1] : '';
+ $GIVN=preg_match("/\n{$sublevel} GIVN (.+)/", $gedcom, $match) ? $match[1] : '';
+ $SURN=preg_match("/\n{$sublevel} SURN (.+)/", $gedcom, $match) ? $match[1] : '';
+ $NSFX=preg_match("/\n{$sublevel} NSFX (.+)/", $gedcom, $match) ? $match[1] : '';
+ $NICK=preg_match("/\n{$sublevel} NICK (.+)/", $gedcom, $match) ? $match[1] : '';
// SURN is an comma-separated list of surnames...
if ($SURN) {
@@ -1867,7 +1247,7 @@ class WT_Person extends WT_GedcomRecord {
} else {
$char = ($bwidth/6.5);
}
- if ($this->canDisplayName()) {
+ if ($this->canShowName()) {
$tmp=$this->getAllNames();
$givn = $tmp[$this->getPrimaryName()]['givn'];
$surn = $tmp[$this->getPrimaryName()]['surname'];
diff --git a/library/WT/Media.php b/library/WT/Media.php
index e370da631b..23643184df 100644
--- a/library/WT/Media.php
+++ b/library/WT/Media.php
@@ -30,62 +30,55 @@ if (!defined('WT_WEBTREES')) {
class WT_Media extends WT_GedcomRecord {
const RECORD_TYPE = 'OBJE';
+ const SQL_FETCH = "SELECT m_gedcom FROM `##media` WHERE m_id=? AND m_file=?";
const URL_PREFIX = 'mediaviewer.php?mid=';
public $title = null; // TODO: these should be private, with getTitle() and getFilename() functions
public $file = null;
// Create a Media object from either raw GEDCOM data or a database row
- public function __construct($data) {
- parent::__construct($data);
+ public function __construct($xref, $gedcom, $pending, $gedcom_id) {
+ parent::__construct($xref, $gedcom, $pending, $gedcom_id);
- if (is_array($data)) {
- // Construct from a row from the database
- $this->file =$data['m_filename'];
- $this->title=$data['m_titl'];
+ // TODO get this data from WT_Fact objects
+ if (preg_match('/\n1 FILE (.+)/', $gedcom.$pending, $match)) {
+ $this->file = $match[1];
} else {
- // Construct from raw GEDCOM data
- if (preg_match('/\n1 FILE (.+)/', $data, $match)) {
- $this->file = $match[1];
- } else {
- $this->file = '';
- }
- if (preg_match('/\n\d TITL (.+)/', $data, $match)) {
- $this->title = $match[1];
- } else {
- $this->title = $this->file;
- }
+ $this->file = '';
+ }
+ if (preg_match('/\n\d TITL (.+)/', $gedcom.$pending, $match)) {
+ $this->title = $match[1];
+ } else {
+ $this->title = $this->file;
}
}
// Implement media-specific privacy logic ...
- protected function _canDisplayDetailsByType($access_level) {
+ protected function _canShowByType($access_level) {
// Hide media objects if they are attached to private records
$linked_ids=WT_DB::prepare(
"SELECT l_from FROM `##link` WHERE l_to=? AND l_file=?"
- )->execute(array($this->xref, $this->ged_id))->fetchOneColumn();
+ )->execute(array($this->xref, $this->gedcom_id))->fetchOneColumn();
foreach ($linked_ids as $linked_id) {
$linked_record=WT_GedcomRecord::getInstance($linked_id);
- if ($linked_record && !$linked_record->canDisplayDetails($access_level)) {
+ if ($linked_record && !$linked_record->canShow($access_level)) {
return false;
}
}
// ... otherwise apply default behaviour
- return parent::_canDisplayDetailsByType($access_level);
+ return parent::_canShowByType($access_level);
}
// Fetch the record from the database
- protected static function fetchGedcomRecord($xref, $ged_id) {
+ protected static function fetchGedcomRecord($xref, $gedcom_id) {
static $statement=null;
if ($statement===null) {
- $statement=WT_DB::prepare(
- "SELECT 'OBJE' AS type, m_id AS xref, m_file AS ged_id, m_gedcom AS gedrec, m_titl, m_filename".
- " FROM `##media` WHERE m_id=? AND m_file=?"
- );
+ $statement=WT_DB::prepare("SELECT m_gedcom FROM `##media` WHERE m_id=? AND m_file=?");
}
- return $statement->execute(array($xref, $ged_id))->fetchOneRow(PDO::FETCH_ASSOC);
+
+ return $statement->execute(array($xref, $gedcom_id))->fetchOne();
}
/**
@@ -93,7 +86,7 @@ class WT_Media extends WT_GedcomRecord {
* @return string
*/
public function getNote() {
- return get_gedcom_value('NOTE', 1, $this->getGedcomRecord());
+ return get_gedcom_value('NOTE', 1, $this->getGedcom());
}
/**
@@ -246,13 +239,13 @@ class WT_Media extends WT_GedcomRecord {
* @return string
*/
public function getMediaType() {
- $mediaType = strtolower(get_gedcom_value('FORM:TYPE', 2, $this->getGedcomRecord()));
+ $mediaType = strtolower(get_gedcom_value('FORM:TYPE', 2, $this->getGedcom()));
return $mediaType;
}
// Is this object marked as a highlighted image?
public function isPrimary() {
- if (preg_match('/\n\d _PRIM ([YN])/', $this->getGedcomRecord(), $match)) {
+ if (preg_match('/\n\d _PRIM ([YN])/', $this->getGedcom(), $match)) {
return $match[1];
} else {
return '';
@@ -341,7 +334,7 @@ class WT_Media extends WT_GedcomRecord {
$downloadstr = ($download) ? '&dl=1' : '';
return
'mediafirewall.php?mid=' . $this->getXref() . $thumbstr . $downloadstr .
- '&amp;ged=' . rawurlencode(get_gedcom_from_id($this->ged_id)) .
+ '&amp;ged=' . rawurlencode(get_gedcom_from_id($this->gedcom_id)) .
'&amp;cb=' . $this->getEtag($which);
}
@@ -425,7 +418,7 @@ class WT_Media extends WT_GedcomRecord {
// If this object has no name, what do we call it?
public function getFallBackName() {
- if ($this->canDisplayDetails()) {
+ if ($this->canShow()) {
return basename($this->file);
} else {
return $this->getXref();
@@ -434,7 +427,7 @@ class WT_Media extends WT_GedcomRecord {
// Get an array of structures containing all the names in the record
public function getAllNames() {
- if (strpos($this->getGedcomRecord(), "\n1 TITL ")) {
+ if (strpos($this->getGedcom(), "\n1 TITL ")) {
// Earlier gedcom versions had level 1 titles
return parent::_getAllNames('TITL', 1);
} else {
diff --git a/library/WT/MenuBar.php b/library/WT/MenuBar.php
index 1cc5d647b7..0798f4cafc 100644
--- a/library/WT/MenuBar.php
+++ b/library/WT/MenuBar.php
@@ -2,7 +2,7 @@
// System for generating menus.
//
// webtrees: Web based Family History software
-// Copyright (C) 2012 webtrees development team.
+// Copyright (C) 2013 webtrees development team.
//
// Derived from PhpGedView
// Copyright (C) 2002 to 2010 PGV Development Team. All rights reserved.
@@ -235,8 +235,8 @@ class WT_MenuBar {
// Add a submenu showing relationship from this person to each of our favorites
foreach (user_favorites_WT_Module::getFavorites(WT_USER_ID) as $favorite) {
if ($favorite['type']=='INDI' && $favorite['gedcom_id']==WT_GED_ID) {
- $person=WT_Person::getInstance($favorite['gid']);
- if ($person instanceof WT_Person) {
+ $person=WT_Individual::getInstance($favorite['gid']);
+ if ($person instanceof WT_Individual) {
$subsubmenu = new WT_Menu(
$person->getFullName(),
'relationship.php?pid1='.$person->getXref().'&amp;pid2='.$pid2.'&amp;ged='.WT_GEDURL,
@@ -517,7 +517,7 @@ class WT_MenuBar {
case 'OBJE':
case 'NOTE':
$obj=WT_GedcomRecord::getInstance($favorite['gid']);
- if ($obj && $obj->canDisplayName()) {
+ if ($obj && $obj->canShowName()) {
$submenu=new WT_Menu($obj->getFullName(), $obj->getHtmlUrl());
$menu->addSubMenu($submenu);
}
diff --git a/library/WT/Note.php b/library/WT/Note.php
index 0f1cedafa0..c9524b286f 100644
--- a/library/WT/Note.php
+++ b/library/WT/Note.php
@@ -30,23 +30,33 @@ if (!defined('WT_WEBTREES')) {
class WT_Note extends WT_GedcomRecord {
const RECORD_TYPE = 'NOTE';
+ const SQL_FETCH = "SELECT o_gedcom FROM `##other` WHERE o_id=? AND o_file=?";
const URL_PREFIX = 'note.php?nid=';
+ // Get the text contents of the note
+ public function getNote() {
+ if (preg_match('/^0 @' . WT_REGEX_TAG . '@ NOTE ?(.*(?:\n1 CONT .*)*)/', $this->gedcom, $match)) {
+ return str_replace("\n1 CONT ", "\n", $match[1]);
+ } else {
+ return null;
+ }
+ }
+
// Implement note-specific privacy logic
- protected function _canDisplayDetailsByType($access_level) {
+ protected function _canShowByType($access_level) {
// Hide notes if they are attached to private records
$linked_ids=WT_DB::prepare(
"SELECT l_from FROM `##link` WHERE l_to=? AND l_file=?"
- )->execute(array($this->xref, $this->ged_id))->fetchOneColumn();
+ )->execute(array($this->xref, $this->gedcom_id))->fetchOneColumn();
foreach ($linked_ids as $linked_id) {
$linked_record=WT_GedcomRecord::getInstance($linked_id);
- if ($linked_record && !$linked_record->canDisplayDetails($access_level)) {
+ if ($linked_record && !$linked_record->canShow($access_level)) {
return false;
}
}
// Apply default behaviour
- return parent::_canDisplayDetailsByType($access_level);
+ return parent::_canShowByType($access_level);
}
// Generate a private version of this record
@@ -55,16 +65,14 @@ class WT_Note extends WT_GedcomRecord {
}
// Fetch the record from the database
- protected static function fetchGedcomRecord($xref, $ged_id) {
+ protected static function fetchGedcomRecord($xref, $gedcom_id) {
static $statement=null;
if ($statement===null) {
- $statement=WT_DB::prepare(
- "SELECT o_type AS type, o_id AS xref, o_file AS ged_id, o_gedcom AS gedrec ".
- "FROM `##other` WHERE o_id=? AND o_file=? AND o_type='NOTE'"
- );
+ $statement=WT_DB::prepare("SELECT o_gedcom FROM `##other` WHERE o_id=? AND o_file=? AND o_type='NOTE'");
}
- return $statement->execute(array($xref, $ged_id))->fetchOneRow(PDO::FETCH_ASSOC);
+
+ return $statement->execute(array($xref, $gedcom_id))->fetchOne();
}
// The 'name' of a note record is the first line. This can be
diff --git a/library/WT/Query/Media.php b/library/WT/Query/Media.php
index 91c1b4a91c..241513846d 100644
--- a/library/WT/Query/Media.php
+++ b/library/WT/Query/Media.php
@@ -67,7 +67,7 @@ class WT_Query_Media {
public static function mediaList($folder, $subfolders, $sort, $filter) {
// All files in the folder, plus external files
$sql =
- "SELECT 'OBJE' AS type, m_id AS xref, m_file AS ged_id, m_gedcom AS gedrec, m_titl, m_filename" .
+ "SELECT m_id AS xref, m_file AS gedcom_id, m_gedcom AS gedcom" .
" FROM `##media`" .
" WHERE m_file=?";
$args = array(
@@ -114,11 +114,11 @@ class WT_Query_Media {
throw new Exception('Bad argument (sort=', $sort, ') in WT_Query_Media::mediaList()');
}
- $rows = WT_DB::prepare($sql)->execute($args)->fetchAll(PDO::FETCH_ASSOC);
+ $rows = WT_DB::prepare($sql)->execute($args)->fetchAll();
$list = array();
foreach ($rows as $row) {
- $media = WT_Media::getInstance($row);
- if ($media->canDisplayDetails()) {
+ $media = WT_Media::getInstance($row->xref, $row->gedcom_id, $row->gedcom);
+ if ($media->canShow()) {
$list[] = $media;
}
}
diff --git a/library/WT/Query/Name.php b/library/WT/Query/Name.php
index 4e04895d48..01a674dbb1 100644
--- a/library/WT/Query/Name.php
+++ b/library/WT/Query/Name.php
@@ -387,7 +387,7 @@ class WT_Query_Name {
// To search for names with no surnames, use $salpha=","
public static function individuals($surn, $salpha, $galpha, $marnm, $fams, $ged_id) {
$sql=
- "SELECT 'INDI' AS type, i_id AS xref, i_file AS ged_id, i_gedcom AS gedrec, n_full ".
+ "SELECT i_id AS xref, i_file AS gedcom_id, i_gedcom AS gedcom, n_full ".
"FROM `##individuals` ".
"JOIN `##name` ON (n_id=i_id AND n_file=i_file) ".
($fams ? "JOIN `##link` ON (n_id=l_from AND n_file=l_file AND l_type='FAMS') " : "").
@@ -413,12 +413,12 @@ class WT_Query_Name {
$sql.=" ORDER BY CASE n_surn WHEN '@N.N.' THEN 1 ELSE 0 END, n_surn COLLATE '".WT_I18N::$collation."', CASE n_givn WHEN '@P.N.' THEN 1 ELSE 0 END, n_givn COLLATE '".WT_I18N::$collation."'";
$list=array();
- $rows=WT_DB::prepare($sql)->fetchAll(PDO::FETCH_ASSOC);
+ $rows=WT_DB::prepare($sql)->fetchAll();
foreach ($rows as $row) {
- $person=WT_Person::getInstance($row);
+ $person=WT_Individual::getInstance($row->xref, $row->gedcom_id, $row->gedcom);
// The name from the database may be private - check the filtered list...
foreach ($person->getAllNames() as $n=>$name) {
- if ($name['fullNN']==$row['n_full']) {
+ if ($name['fullNN']==$row->n_full) {
$person->setPrimaryName($n);
// We need to clone $person, as we may have multiple references to the
// same person in this list, and the "primary name" would otherwise
diff --git a/library/WT/Report/Base.php b/library/WT/Report/Base.php
index 30e3cd9828..e39b81b338 100644
--- a/library/WT/Report/Base.php
+++ b/library/WT/Report/Base.php
@@ -458,7 +458,7 @@ class Element {
$t = str_replace(array("<br>", "&nbsp;"), array("\n", " "), $t);
if (!WT_RNEW) {
$t = strip_tags($t);
- $t = unhtmlentities($t);
+ $t = htmlspecialchars_decode($t);
}
$this->text .= $t;
@@ -975,7 +975,7 @@ class Footnote extends Element {
$t = str_replace(array("<br>", "&nbsp;"), array("\n", " "), $t);
if (!WT_RNEW) {
$t = strip_tags($t);
- $t = unhtmlentities($t);
+ $t = htmlspecialchars_decode($t);
}
$this->text .= $t;
return 0;
@@ -1669,7 +1669,7 @@ function GedcomSHandler($attrs) {
$newgedrec = "";
if (count($tags)<2) {
$tmp=WT_GedcomRecord::getInstance($attrs['id']);
- $newgedrec=$tmp ? $tmp->getGedcomRecord() : '';
+ $newgedrec=$tmp ? $tmp->getGedcom() : '';
}
if (empty($newgedrec)) {
$tgedrec = $gedrec;
@@ -1680,14 +1680,14 @@ function GedcomSHandler($attrs) {
$newgedrec = $vars[$match[1]]['gedcom'];
} else {
$tmp=WT_GedcomRecord::getInstance($match[1]);
- $newgedrec=$tmp ? $tmp->getGedcomRecord() : '';
+ $newgedrec=$tmp ? $tmp->getGedcom() : '';
}
} else {
if (preg_match("/@(.+)/", $tag, $match)) {
$gmatch = array();
if (preg_match("/\d $match[1] @([^@]+)@/", $tgedrec, $gmatch)) {
$tmp=WT_GedcomRecord::getInstance($gmatch[1]);
- $newgedrec=$tmp ? $tmp->getGedcomRecord() : '';
+ $newgedrec=$tmp ? $tmp->getGedcom() : '';
$tgedrec = $newgedrec;
} else {
$newgedrec = "";
@@ -1942,7 +1942,7 @@ function GetPersonNameSHandler($attrs) {
if (is_null($record)) {
return;
}
- if (!$record->canDisplayName()) {
+ if (!$record->canShowName()) {
$currentElement->addText(WT_I18N::translate('Private'));
} else {
$name = $record->getFullName();
@@ -2189,12 +2189,7 @@ function RepeatTagEHandler() {
// Save original values
array_push($parserStack, $parser);
$oldgedrec = $gedrec;
- // PHP 5.2.3 has a bug with foreach (), so don't use that here, while 5.2.3 is on the market
- // while () has the fastest execution speed
- $count = count($repeats);
- $i = 0;
- while ($i < $count) {
- $gedrec = $repeats[$i];
+ foreach ($repeats as $gedrec) {
//-- start the sax parser
$repeat_parser = xml_parser_create();
$parser = $repeat_parser;
@@ -2211,7 +2206,6 @@ function RepeatTagEHandler() {
exit;
}
xml_parser_free($repeat_parser);
- $i++;
}
// Restore original values
$gedrec = $oldgedrec;
@@ -2334,28 +2328,21 @@ function FactsSHandler($attrs) {
$tag = $vars[$match[1]]['id'];
}
+ $record = WT_GedcomRecord::getInstance($id);
if (empty($attrs['diff']) && !empty($id)) {
- $record = WT_GedcomRecord::getInstance($id);
$facts = $record->getFacts();
- if (!is_array($facts)) {
- $facts = array($facts);
- }
sort_facts($facts);
$repeats = array();
$nonfacts=explode(',', $tag);
foreach ($facts as $event) {
if (!in_array($event->getTag(), $nonfacts)) {
- $repeats[]=$event->getGedComRecord();
+ $repeats[]=$event->getGedcom();
}
}
} else {
- $record = new WT_GedcomRecord($gedrec);
- $oldrecord = WT_GedcomRecord::getInstance($record->getXref());
- $oldrecord->diffMerge($record);
- $facts = $oldrecord->getFacts();
- foreach ($facts as $fact) {
- if ($fact->getIsNew() && $fact->getTag()<>'CHAN') {
- $repeats[]=$fact->getGedcomRecord();
+ foreach ($record->getFacts as $fact) {
+ if ($fact->isNew() && $fact->getTag()<>'CHAN') {
+ $repeats[]=$fact->getGedcom();
}
}
}
@@ -2604,7 +2591,7 @@ function FootnoteSHandler($attrs) {
$id = $match[2];
}
$record=WT_GedcomRecord::GetInstance($id);
- if ($record && $record->canDisplayDetails()) {
+ if ($record && $record->canShow()) {
array_push($printDataStack, $printData);
$printData = true;
$style = "";
@@ -2665,7 +2652,7 @@ function AgeAtDeathSHandler() {
$id = "";
$match = array();
if (preg_match("/0 @(.+)@/", $gedrec, $match)) {
- $person=WT_Person::getInstance($match[1]);
+ $person=WT_Individual::getInstance($match[1]);
// Recorded age
$fact_age=get_gedcom_value('AGE', 2, $gedrec);
if ($fact_age=='') {
@@ -2776,11 +2763,11 @@ function HighlightedImageSHandler($attrs) {
if (!empty($attrs['width'])) $width = (int)$attrs['width'];
if (!empty($attrs['height'])) $height = (int)$attrs['height'];
- $person=WT_Person::getInstance($id);
+ $person=WT_Individual::getInstance($id);
$mediaobject = $person->findHighlightedMedia();
if ($mediaobject) {
$attributes=$mediaobject->getImageAttributes('thumb');
- if (in_array($attributes['ext'], array('GIF','JPG','PNG','SWF','PSD','BMP','TIFF','TIFF','JPC','JP2','JPX','JB2','SWC','IFF','WBMP','XBM')) && $mediaobject->canDisplayDetails() && $mediaobject->fileExists('thumb')) {
+ if (in_array($attributes['ext'], array('GIF','JPG','PNG','SWF','PSD','BMP','TIFF','TIFF','JPC','JP2','JPX','JB2','SWC','IFF','WBMP','XBM')) && $mediaobject->canShow() && $mediaobject->fileExists('thumb')) {
if (($width>0) and ($height==0)) {
$perc = $width / $attributes['adjW'];
$height= round($attributes['adjH']*$perc);
@@ -2848,7 +2835,7 @@ function ImageSHandler($attrs) {
if (preg_match("/\d OBJE @(.+)@/", $gedrec, $match)) {
$mediaobject=WT_Media::getInstance($match[1], WT_GED_ID);
$attributes=$mediaobject->getImageAttributes('thumb');
- if (in_array($attributes['ext'], array('GIF','JPG','PNG','SWF','PSD','BMP','TIFF','TIFF','JPC','JP2','JPX','JB2','SWC','IFF','WBMP','XBM')) && $mediaobject->canDisplayDetails() && $mediaobject->fileExists('thumb')) {
+ if (in_array($attributes['ext'], array('GIF','JPG','PNG','SWF','PSD','BMP','TIFF','TIFF','JPC','JP2','JPX','JB2','SWC','IFF','WBMP','XBM')) && $mediaobject->canShow() && $mediaobject->fileExists('thumb')) {
if (($width>0) and ($height==0)) {
$perc = $width / $attributes['adjW'];
$height= round($attributes['adjH']*$perc);
@@ -2972,7 +2959,7 @@ function ListSHandler($attrs) {
switch ($listname) {
case "pending":
$rows=WT_DB::prepare(
- "SELECT CASE new_gedcom WHEN '' THEN old_gedcom ELSE new_gedcom END AS gedcom".
+ "SELECT xref, gedcom_id, CASE new_gedcom WHEN '' THEN old_gedcom ELSE new_gedcom END AS gedcom".
" FROM `##change`".
" WHERE (xref, change_id) IN (".
" SELECT xref, MAX(change_id)".
@@ -2983,7 +2970,7 @@ function ListSHandler($attrs) {
)->execute(array(WT_GED_ID))->fetchAll();
$list=array();
foreach ($rows as $row) {
- $list[]=new WT_GedcomRecord($row->gedcom);
+ $list[] = WT_GedcomRecord::getInstance($row->xref, $row->gedcom_id, $row->gedcom);
}
break;
case "individual":
@@ -2995,7 +2982,7 @@ function ListSHandler($attrs) {
foreach ($attrs as $attr=>$value) {
if ((strpos($attr, "filter")===0) && $value) {
// Substitute global vars
- $value=preg_replace('/\$(\w+)/e', '$vars["\\1"]["id"]', $value);
+ $value=preg_replace_callback('/\$(\w+)/', function($matches) use ($vars) { return $vars[$matches[1]]['id']; }, $value);
// Convert the various filters into SQL
if (preg_match('/^(\w+):DATE (LTE|GTE) (.+)$/', $value, $match)) {
$sql_join[]="JOIN `##dates` AS {$attr} ON ({$attr}.d_file={$sql_col_prefix}file AND {$attr}.d_gid={$sql_col_prefix}id)";
@@ -3171,7 +3158,7 @@ function ListSHandler($attrs) {
if ($filters) {
foreach ($list as $key=>$record) {
foreach ($filters as $filter) {
- if (!preg_match("/".$filter."/i", $record->getGedcomRecord())) {
+ if (!preg_match("/".$filter."/i", $record->getGedcom())) {
unset($list[$key]);
break;
}
@@ -3182,7 +3169,7 @@ function ListSHandler($attrs) {
$mylist = array();
foreach ($list as $indi) {
$key=$indi->getXref();
- $grec=$indi->getGedcomRecord();
+ $grec=$indi->getGedcom();
$keep = true;
foreach ($filters2 as $filter) {
if ($keep) {
@@ -3247,10 +3234,10 @@ function ListSHandler($attrs) {
uasort($list, array("WT_GedcomRecord", "CompareChanDate"));
break;
case "BIRT:DATE":
- uasort($list, array("WT_Person", "CompareBirtDate"));
+ uasort($list, array("WT_Individual", "CompareBirtDate"));
break;
case "DEAT:DATE":
- uasort($list, array("WT_Person", "CompareDeatDate"));
+ uasort($list, array("WT_Individual", "CompareDeatDate"));
break;
case "MARR:DATE":
uasort($list, array("WT_Family", "CompareMarrDate"));
@@ -3315,8 +3302,8 @@ function ListEHandler() {
$list_total = count($list);
$list_private = 0;
foreach ($list as $record) {
- if ($record->canDisplayDetails()) {
- $gedrec = $record->getGedcomRecord();
+ if ($record->canShow()) {
+ $gedrec = $record->getGedcom();
//-- start the sax parser
$repeat_parser = xml_parser_create();
$parser = $repeat_parser;
@@ -3411,7 +3398,7 @@ function RelativesSHandler($attrs) {
}
$list = array();
- $person = WT_Person::getInstance($id);
+ $person = WT_Individual::getInstance($id);
if (!empty($person)) {
$list[$id] = $person;
switch ($group) {
@@ -3558,7 +3545,7 @@ function RelativesEHandler() {
continue; // key can be something like "empty7"
}
$tmp=WT_GedcomRecord::getInstance($key);
- $gedrec = $tmp->getGedcomRecord();
+ $gedrec = $tmp->getGedcom();
//-- start the sax parser
$repeat_parser = xml_parser_create();
$parser = $repeat_parser;
diff --git a/library/WT/Repository.php b/library/WT/Repository.php
index c104238a68..e1e6fefd17 100644
--- a/library/WT/Repository.php
+++ b/library/WT/Repository.php
@@ -30,19 +30,18 @@ if (!defined('WT_WEBTREES')) {
class WT_Repository extends WT_GedcomRecord {
const RECORD_TYPE = 'REPO';
+ const SQL_FETCH = "SELECT o_gedcom FROM `##other` WHERE o_id=? AND o_file=?";
const URL_PREFIX = 'repo.php?rid=';
// Fetch the record from the database
- protected static function fetchGedcomRecord($xref, $ged_id) {
+ protected static function fetchGedcomRecord($xref, $gedcom_id) {
static $statement=null;
if ($statement===null) {
- $statement=WT_DB::prepare(
- "SELECT o_type AS type, o_id AS xref, o_file AS ged_id, o_gedcom AS gedrec ".
- "FROM `##other` WHERE o_id=? AND o_file=?"
- );
+ $statement=WT_DB::prepare("SELECT o_gedcom FROM `##other` WHERE o_id=? AND o_file=?");
}
- return $statement->execute(array($xref, $ged_id))->fetchOneRow(PDO::FETCH_ASSOC);
+
+ return $statement->execute(array($xref, $gedcom_id))->fetchOne();
}
// Generate a private version of this record
diff --git a/library/WT/Source.php b/library/WT/Source.php
index 3664e4af69..67c42c7793 100644
--- a/library/WT/Source.php
+++ b/library/WT/Source.php
@@ -30,21 +30,22 @@ if (!defined('WT_WEBTREES')) {
class WT_Source extends WT_GedcomRecord {
const RECORD_TYPE = 'SOUR';
+ const SQL_FETCH = "SELECT s_gedcom FROM `##sources` WHERE s_id=? AND s_file=?";
const URL_PREFIX = 'source.php?sid=';
// Implement source-specific privacy logic
- protected function _canDisplayDetailsByType($access_level) {
+ protected function _canShowByType($access_level) {
// Hide sources if they are attached to private repositories ...
- preg_match_all('/\n1 REPO @(.+)@/', $this->_gedrec, $matches);
+ preg_match_all('/\n1 REPO @(.+)@/', $this->gedcom, $matches);
foreach ($matches[1] as $match) {
$repo=WT_Repository::getInstance($match);
- if ($repo && !$repo->canDisplayDetails($access_level)) {
+ if ($repo && !$repo->canShow($access_level)) {
return false;
}
}
// ... otherwise apply default behaviour
- return parent::_canDisplayDetailsByType($access_level);
+ return parent::_canShowByType($access_level);
}
// Generate a private version of this record
@@ -53,20 +54,18 @@ class WT_Source extends WT_GedcomRecord {
}
// Fetch the record from the database
- protected static function fetchGedcomRecord($xref, $ged_id) {
+ protected static function fetchGedcomRecord($xref, $gedcom_id) {
static $statement=null;
if ($statement===null) {
- $statement=WT_DB::prepare(
- "SELECT 'SOUR' AS type, s_id AS xref, s_file AS ged_id, s_gedcom AS gedrec ".
- "FROM `##sources` WHERE s_id=? AND s_file=?"
- );
+ $statement=WT_DB::prepare("SELECT s_gedcom FROM `##sources` WHERE s_id=? AND s_file=?");
}
- return $statement->execute(array($xref, $ged_id))->fetchOneRow(PDO::FETCH_ASSOC);
+
+ return $statement->execute(array($xref, $gedcom_id))->fetchOne();
}
public function getAuth() {
- return get_gedcom_value('AUTH', 1, $this->getGedcomRecord());
+ return get_gedcom_value('AUTH', 1, $this->getGedcom());
}
// Get an array of structures containing all the names in the record
diff --git a/library/WT/Stats.php b/library/WT/Stats.php
index 3f538e1651..43bae5f13d 100644
--- a/library/WT/Stats.php
+++ b/library/WT/Stats.php
@@ -254,7 +254,7 @@ class WT_Stats {
}
function gedcomRootID() {
- $root = WT_Person::getInstance(get_gedcom_setting(WT_GED_ID, 'PEDIGREE_ROOT_ID'));
+ $root = WT_Individual::getInstance(get_gedcom_setting(WT_GED_ID, 'PEDIGREE_ROOT_ID'));
$root = substr($root, 0, stripos($root, "@") );
return $root;
}
@@ -842,7 +842,7 @@ class WT_Stats {
switch($type) {
default:
case 'full':
- if ($record->canDisplayDetails()) {
+ if ($record->canShow()) {
$result=$record->format_list('span', false, $record->getFullName());
} else {
$result=WT_I18N::translate('This information is private and cannot be shown.');
@@ -996,7 +996,7 @@ class WT_Stats {
$surn_countries=array();
$indis = WT_Query_Name::individuals(utf8_strtoupper($surname), '', '', false, false, WT_GED_ID);
foreach ($indis as $person) {
- if (preg_match_all('/^2 PLAC (?:.*, *)*(.*)/m', $person->getGedcomRecord(), $matches)) {
+ if (preg_match_all('/^2 PLAC (?:.*, *)*(.*)/m', $person->getGedcom(), $matches)) {
// webtrees uses 3 letter country codes and localised country names, but google uses 2 letter codes.
foreach ($matches[1] as $country) {
$country=trim($country);
@@ -1377,11 +1377,11 @@ class WT_Stats {
);
if (!isset($rows[0])) {return '';}
$row = $rows[0];
- $person=WT_Person::getInstance($row['id']);
+ $person=WT_Individual::getInstance($row['id']);
switch($type) {
default:
case 'full':
- if ($person->canDisplayName()) {
+ if ($person->canShowName()) {
$result=$person->format_list('span', false, $person->getFullName());
} else {
$result= WT_I18N::translate('This information is private and cannot be shown.');
@@ -1435,7 +1435,7 @@ class WT_Stats {
if (!isset($rows[0])) {return '';}
$top10 = array();
foreach ($rows as $row) {
- $person = WT_Person::getInstance($row['deathdate']);
+ $person = WT_Individual::getInstance($row['deathdate']);
$age = $row['age'];
if ((int)($age/365.25)>0) {
$age = (int)($age/365.25).'y';
@@ -1445,7 +1445,7 @@ class WT_Stats {
$age = $age.'d';
}
$age = get_age_at_event($age, true);
- if ($person->canDisplayDetails()) {
+ if ($person->canShow()) {
if ($type == 'list') {
$top10[]="<li><a href=\"".$person->getHtmlUrl()."\">".$person->getFullName()."</a> (".$age.")"."</li>";
} else {
@@ -1502,7 +1502,7 @@ class WT_Stats {
if (!isset($rows)) {return 0;}
$top10 = array();
foreach ($rows as $row) {
- $person=WT_Person::getInstance($row['id']);
+ $person=WT_Individual::getInstance($row['id']);
$age = (WT_CLIENT_JD-$row['age']);
if ((int)($age/365.25)>0) {
$age = (int)($age/365.25).'y';
@@ -1776,7 +1776,7 @@ class WT_Stats {
switch($type) {
default:
case 'full':
- if ($record->canDisplayDetails()) {
+ if ($record->canShow()) {
$result=$record->format_list('span', false, $record->getFullName());
} else {
$result=WT_I18N::translate('This information is private and cannot be shown.');
@@ -1871,11 +1871,11 @@ class WT_Stats {
if (!isset($rows[0])) {return '';}
$row=$rows[0];
if (isset($row['famid'])) $family=WT_Family::getInstance($row['famid']);
- if (isset($row['i_id'])) $person=WT_Person::getInstance($row['i_id']);
+ if (isset($row['i_id'])) $person=WT_Individual::getInstance($row['i_id']);
switch($type) {
default:
case 'full':
- if ($family->canDisplayDetails()) {
+ if ($family->canShow()) {
$result=$family->format_list('span', false, $person->getFullName());
} else {
$result=WT_I18N::translate('This information is private and cannot be shown.');
@@ -1990,7 +1990,7 @@ class WT_Stats {
$husb = $family->getHusband();
$wife = $family->getWife();
if (($husb->getAllDeathDates() && $wife->getAllDeathDates()) || !$husb->isDead() || !$wife->isDead()) {
- if ($family->canDisplayDetails()) {
+ if ($family->canShow()) {
if ($type == 'list') {
$top10[] = "<li><a href=\"".$family->getHtmlUrl()."\">".$family->getFullName()."</a> (".$age.")"."</li>";
} else {
@@ -2054,7 +2054,7 @@ class WT_Stats {
$age = $age.'d';
}
$age = get_age_at_event($age, true);
- if ($family->canDisplayDetails()) {
+ if ($family->canShow()) {
if ($type == 'list') {
$top10[] = "<li><a href=\"".$family->getHtmlUrl()."\">".$family->getFullName()."</a> (".$age.")"."</li>";
} else {
@@ -2102,11 +2102,11 @@ class WT_Stats {
);
if (!isset($rows[0])) {return '';}
$row=$rows[0];
- if (isset($row['id'])) $person=WT_Person::getInstance($row['id']);
+ if (isset($row['id'])) $person=WT_Individual::getInstance($row['id']);
switch($type) {
default:
case 'full':
- if ($person->canDisplayDetails()) {
+ if ($person->canShow()) {
$result=$person->format_list('span', false, $person->getFullName());
} else {
$result=WT_I18N::translate('This information is private and cannot be shown.');
@@ -2523,7 +2523,7 @@ class WT_Stats {
switch($type) {
default:
case 'full':
- if ($family->canDisplayDetails()) {
+ if ($family->canShow()) {
$result=$family->format_list('span', false, $family->getFullName());
} else {
$result = WT_I18N::translate('This information is private and cannot be shown.');
@@ -2556,7 +2556,7 @@ class WT_Stats {
$top10 = array();
for ($c = 0; $c < $total; $c++) {
$family=WT_Family::getInstance($rows[$c]['id']);
- if ($family->canDisplayDetails()) {
+ if ($family->canShow()) {
if ($type == 'list') {
$top10[]=
'<li><a href="'.$family->getHtmlUrl().'">'.$family->getFullName().'</a> - '.
@@ -2618,10 +2618,10 @@ class WT_Stats {
if ($one) $dist = array();
foreach ($rows as $fam) {
$family = WT_Family::getInstance($fam['family']);
- $child1 = WT_Person::getInstance($fam['ch1']);
- $child2 = WT_Person::getInstance($fam['ch2']);
+ $child1 = WT_Individual::getInstance($fam['ch1']);
+ $child2 = WT_Individual::getInstance($fam['ch2']);
if ($type == 'name') {
- if ($child1->canDisplayDetails() && $child2->canDisplayDetails()) {
+ if ($child1->canShow() && $child2->canShow()) {
$return = '<a href="'.$child2->getHtmlUrl().'">'.$child2->getFullName().'</a> ';
$return .= WT_I18N::translate('and').' ';
$return .= '<a href="'.$child1->getHtmlUrl().'">'.$child1->getFullName().'</a>';
@@ -2645,7 +2645,7 @@ class WT_Stats {
}
if ($type == 'list') {
if ($one && !in_array($fam['family'], $dist)) {
- if ($child1->canDisplayDetails() && $child2->canDisplayDetails()) {
+ if ($child1->canShow() && $child2->canShow()) {
$return = "<li>";
$return .= "<a href=\"".$child2->getHtmlUrl()."\">".$child2->getFullName()."</a> ";
$return .= WT_I18N::translate('and')." ";
@@ -2656,7 +2656,7 @@ class WT_Stats {
$top10[] = $return;
$dist[] = $fam['family'];
}
- } else if (!$one && $child1->canDisplayDetails() && $child2->canDisplayDetails()) {
+ } else if (!$one && $child1->canShow() && $child2->canShow()) {
$return = "<li>";
$return .= "<a href=\"".$child2->getHtmlUrl()."\">".$child2->getFullName()."</a> ";
$return .= WT_I18N::translate('and')." ";
@@ -2667,7 +2667,7 @@ class WT_Stats {
$top10[] = $return;
}
} else {
- if ($child1->canDisplayDetails() && $child2->canDisplayDetails()) {
+ if ($child1->canShow() && $child2->canShow()) {
$return = $child2->format_list('span', false, $child2->getFullName());
$return .= "<br>".WT_I18N::translate('and')."<br>";
$return .= $child1->format_list('span', false, $child1->getFullName());
@@ -2830,14 +2830,14 @@ class WT_Stats {
$chl = array();
foreach ($rows as $row) {
$family=WT_Family::getInstance($row['id']);
- if ($family->canDisplayDetails()) {
+ if ($family->canShow()) {
if ($tot==0) {
$per = 0;
} else {
$per = round(100 * $row['tot'] / $tot, 0);
}
$chd .= self::_array_to_extended_encoding(array($per));
- $chl[] = strip_tags(unhtmlentities($family->getFullName())).' - '.WT_I18N::number($row['tot']);
+ $chl[] = htmlspecialchars_decode(strip_tags($family->getFullName())).' - '.WT_I18N::number($row['tot']);
}
}
$chl = rawurlencode(join('|', $chl));
@@ -2968,7 +2968,7 @@ class WT_Stats {
$top10 = array();
foreach ($rows as $row) {
$family=WT_Family::getInstance($row['family']);
- if ($family->canDisplayDetails()) {
+ if ($family->canShow()) {
if ($type == 'list') {
$top10[] = "<li><a href=\"".$family->getHtmlUrl()."\">".$family->getFullName()."</a></li>";
} else {
@@ -3085,7 +3085,7 @@ class WT_Stats {
$top10 = array();
foreach ($rows as $row) {
$family=WT_Family::getInstance($row['id']);
- if ($family->canDisplayDetails()) {
+ if ($family->canShow()) {
if ($type == 'list') {
$top10[]=
'<li><a href="'.$family->getHtmlUrl().'">'.$family->getFullName().'</a> - '.
diff --git a/library/phpmailer/class.phpmailer.php b/library/phpmailer/class.phpmailer.php
index 3c4f95bcd4..bfb8ecad01 100644
--- a/library/phpmailer/class.phpmailer.php
+++ b/library/phpmailer/class.phpmailer.php
@@ -2,15 +2,16 @@
/*~ class.phpmailer.php
.---------------------------------------------------------------------------.
| Software: PHPMailer - PHP email class |
-| Version: 5.2 |
-| Site: https://code.google.com/a/apache-extras.org/p/phpmailer/ |
+| Version: 5.2.6 |
+| Site: https://github.com/PHPMailer/PHPMailer/ |
| ------------------------------------------------------------------------- |
-| Admin: Jim Jagielski (project admininistrator) |
+| Admins: Marcus Bointon |
+| Admins: Jim Jagielski |
| Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
-| : Marcus Bointon (coolbru) coolbru@users.sourceforge.net |
+| : Marcus Bointon (coolbru) phpmailer@synchromedia.co.uk |
| : Jim Jagielski (jimjag) jimjag@gmail.com |
| Founder: Brent R. Matzelle (original founder) |
-| Copyright (c) 2010-2011, Jim Jagielski. All Rights Reserved. |
+| Copyright (c) 2010-2012, Jim Jagielski. All Rights Reserved. |
| Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved. |
| Copyright (c) 2001-2003, Brent R. Matzelle |
| ------------------------------------------------------------------------- |
@@ -23,20 +24,25 @@
*/
/**
- * PHPMailer - PHP email transport class
+ * PHPMailer - PHP email creation and transport class
* NOTE: Requires PHP version 5 or later
* @package PHPMailer
* @author Andy Prevost
* @author Marcus Bointon
* @author Jim Jagielski
- * @copyright 2010 - 2011 Jim Jagielski
+ * @copyright 2010 - 2012 Jim Jagielski
* @copyright 2004 - 2009 Andy Prevost
- * @version $Id$
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
*/
-if (version_compare(PHP_VERSION, '5.0.0', '<') ) exit("Sorry, this version of PHPMailer will only run on PHP version 5 or greater!\n");
+if (version_compare(PHP_VERSION, '5.0.0', '<') ) {
+ exit("Sorry, PHPMailer will only run on PHP version 5 or greater!\n");
+}
+/**
+ * PHP email creation and transport class
+ * @package PHPMailer
+ */
class PHPMailer {
/////////////////////////////////////////////////
@@ -53,7 +59,7 @@ class PHPMailer {
* Sets the CharSet of the message.
* @var string
*/
- public $CharSet = 'UTF-8';
+ public $CharSet = 'iso-8859-1';
/**
* Sets the Content-type of the message.
@@ -87,35 +93,52 @@ class PHPMailer {
public $FromName = 'Root User';
/**
- * Sets the Sender email (Return-Path) of the message. If not empty,
- * will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
+ * Sets the Sender email (Return-Path) of the message.
+ * If not empty, will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
* @var string
*/
public $Sender = '';
/**
+ * Sets the Return-Path of the message. If empty, it will
+ * be set to either From or Sender.
+ * @var string
+ */
+ public $ReturnPath = '';
+
+ /**
* Sets the Subject of the message.
* @var string
*/
public $Subject = '';
/**
- * Sets the Body of the message. This can be either an HTML or text body.
- * If HTML then run IsHTML(true).
+ * An HTML or plain text message body.
+ * If HTML then call IsHTML(true).
* @var string
*/
public $Body = '';
/**
- * Sets the text-only body of the message. This automatically sets the
- * email to multipart/alternative. This body can be read by mail
- * clients that do not have HTML email capability such as mutt. Clients
- * that can read HTML will view the normal Body.
+ * The plain-text message body.
+ * This body can be read by mail clients that do not have HTML email
+ * capability such as mutt & Eudora.
+ * Clients that can read HTML will view the normal Body.
* @var string
*/
public $AltBody = '';
/**
+ * An iCal message part body
+ * Only supported in simple alt or alt_inline message types
+ * To generate iCal events, use the bundled extras/EasyPeasyICS.php class or iCalcreator
+ * @link http://sprain.ch/blog/downloads/php-class-easypeasyics-create-ical-files-with-php/
+ * @link http://kigkonsult.se/iCalcreator/
+ * @var string
+ */
+ public $Ical = '';
+
+ /**
* Stores the complete compiled MIME message body.
* @var string
* @access protected
@@ -130,6 +153,13 @@ class PHPMailer {
protected $MIMEHeader = '';
/**
+ * Stores the extra header list which CreateHeader() doesn't fold in
+ * @var string
+ * @access protected
+ */
+ protected $mailHeader = '';
+
+ /**
* Sets word wrapping on the body of the message to a given number of
* characters.
* @var int
@@ -149,6 +179,13 @@ class PHPMailer {
public $Sendmail = '/usr/sbin/sendmail';
/**
+ * Determine if mail() uses a fully sendmail compatible MTA that
+ * supports sendmail's "-oi -f" options
+ * @var boolean
+ */
+ public $UseSendmailOptions = true;
+
+ /**
* Path to PHPMailer plugins. Useful if the SMTP class
* is in a different directory than the PHP include path.
* @var string
@@ -176,12 +213,21 @@ class PHPMailer {
*/
public $MessageID = '';
+ /**
+ * Sets the message Date to be used in the Date header.
+ * If empty, the current date will be added.
+ * @var string
+ */
+ public $MessageDate = '';
+
/////////////////////////////////////////////////
// PROPERTIES FOR SMTP
/////////////////////////////////////////////////
/**
- * Sets the SMTP hosts. All hosts must be separated by a
+ * Sets the SMTP hosts.
+ *
+ * All hosts must be separated by a
* semicolon. You can also specify a different port
* for each host by using this format: [hostname:port]
* (e.g. "smtp1.example.com:25;smtp2.example.com").
@@ -203,8 +249,7 @@ class PHPMailer {
public $Helo = '';
/**
- * Sets connection prefix.
- * Options are "", "ssl" or "tls"
+ * Sets connection prefix. Options are "", "ssl" or "tls"
* @var string
*/
public $SMTPSecure = '';
@@ -228,6 +273,24 @@ class PHPMailer {
public $Password = '';
/**
+ * Sets SMTP auth type. Options are LOGIN | PLAIN | NTLM | CRAM-MD5 (default LOGIN)
+ * @var string
+ */
+ public $AuthType = '';
+
+ /**
+ * Sets SMTP realm.
+ * @var string
+ */
+ public $Realm = '';
+
+ /**
+ * Sets SMTP workstation.
+ * @var string
+ */
+ public $Workstation = '';
+
+ /**
* Sets the SMTP server timeout in seconds.
* This function will not work with the win32 version.
* @var int
@@ -241,6 +304,13 @@ class PHPMailer {
public $SMTPDebug = false;
/**
+ * Sets the function/method to use for debugging output.
+ * Right now we only honor "echo" or "error_log"
+ * @var string
+ */
+ public $Debugoutput = "echo";
+
+ /**
* Prevents the SMTP connection from being closed after each mail
* sending. If this is set to true then to close the connection
* requires an explicit call to SmtpClose().
@@ -255,60 +325,89 @@ class PHPMailer {
*/
public $SingleTo = false;
- /**
+ /**
+ * Should we generate VERP addresses when sending via SMTP?
+ * @link http://en.wikipedia.org/wiki/Variable_envelope_return_path
+ * @var bool
+ */
+ public $do_verp = false;
+
+ /**
* If SingleTo is true, this provides the array to hold the email addresses
* @var bool
*/
public $SingleToArray = array();
- /**
- * Provides the ability to change the line ending
+ /**
+ * Should we allow sending messages with empty body?
+ * @var bool
+ */
+ public $AllowEmpty = false;
+
+ /**
+ * Provides the ability to change the generic line ending
+ * NOTE: The default remains '\n'. We force CRLF where we KNOW
+ * it must be used via self::CRLF
* @var string
*/
public $LE = "\n";
- /**
- * Used with DKIM DNS Resource Record
+ /**
+ * Used with DKIM Signing
+ * required parameter if DKIM is enabled
+ *
+ * domain selector example domainkey
* @var string
*/
- public $DKIM_selector = 'phpmailer';
+ public $DKIM_selector = '';
/**
- * Used with DKIM DNS Resource Record
- * optional, in format of email address 'you@yourdomain.com'
+ * Used with DKIM Signing
+ * required if DKIM is enabled, in format of email address 'you@yourdomain.com' typically used as the source of the email
* @var string
*/
public $DKIM_identity = '';
/**
- * Used with DKIM DNS Resource Record
+ * Used with DKIM Signing
+ * optional parameter if your private key requires a passphras
* @var string
*/
public $DKIM_passphrase = '';
/**
- * Used with DKIM DNS Resource Record
- * optional, in format of email address 'you@yourdomain.com'
+ * Used with DKIM Singing
+ * required if DKIM is enabled, in format of email address 'domain.com'
* @var string
*/
public $DKIM_domain = '';
/**
- * Used with DKIM DNS Resource Record
- * optional, in format of email address 'you@yourdomain.com'
+ * Used with DKIM Signing
+ * required if DKIM is enabled, path to private key file
* @var string
*/
public $DKIM_private = '';
/**
- * Callback Action function name
- * the function that handles the result of the send email action. Parameters:
+ * Callback Action function name.
+ * The function that handles the result of the send email action.
+ * It is called out by Send() for each email sent.
+ *
+ * Value can be:
+ * - 'function_name' for function names
+ * - 'Class::Method' for static method calls
+ * - array($object, 'Method') for calling methods on $object
+ * See http://php.net/is_callable manual page for more details.
+ *
+ * Parameters:
* bool $result result of the send action
* string $to email address of the recipient
* string $cc cc email addresses
* string $bcc bcc email addresses
* string $subject the subject
* string $body the email body
+ * string $from email address of sender
* @var string
*/
public $action_function = ''; //'callbackAction';
@@ -317,11 +416,11 @@ class PHPMailer {
* Sets the PHPMailer Version number
* @var string
*/
- public $Version = '5.2';
+ public $Version = '5.2.6';
/**
* What to use in the X-Mailer header
- * @var string
+ * @var string NULL for default, whitespace for None, or actual string to use
*/
public $XMailer = '';
@@ -329,21 +428,85 @@ class PHPMailer {
// PROPERTIES, PRIVATE AND PROTECTED
/////////////////////////////////////////////////
- protected $smtp = NULL;
+ /**
+ * @var SMTP An instance of the SMTP sender class
+ * @access protected
+ */
+ protected $smtp = null;
+ /**
+ * @var array An array of 'to' addresses
+ * @access protected
+ */
protected $to = array();
+ /**
+ * @var array An array of 'cc' addresses
+ * @access protected
+ */
protected $cc = array();
+ /**
+ * @var array An array of 'bcc' addresses
+ * @access protected
+ */
protected $bcc = array();
+ /**
+ * @var array An array of reply-to name and address
+ * @access protected
+ */
protected $ReplyTo = array();
+ /**
+ * @var array An array of all kinds of addresses: to, cc, bcc, replyto
+ * @access protected
+ */
protected $all_recipients = array();
+ /**
+ * @var array An array of attachments
+ * @access protected
+ */
protected $attachment = array();
+ /**
+ * @var array An array of custom headers
+ * @access protected
+ */
protected $CustomHeader = array();
+ /**
+ * @var string The message's MIME type
+ * @access protected
+ */
protected $message_type = '';
+ /**
+ * @var array An array of MIME boundary strings
+ * @access protected
+ */
protected $boundary = array();
+ /**
+ * @var array An array of available languages
+ * @access protected
+ */
protected $language = array();
+ /**
+ * @var integer The number of errors encountered
+ * @access protected
+ */
protected $error_count = 0;
+ /**
+ * @var string The filename of a DKIM certificate file
+ * @access protected
+ */
protected $sign_cert_file = '';
+ /**
+ * @var string The filename of a DKIM key file
+ * @access protected
+ */
protected $sign_key_file = '';
+ /**
+ * @var string The password of a DKIM key
+ * @access protected
+ */
protected $sign_key_pass = '';
+ /**
+ * @var boolean Whether to throw exceptions for errors
+ * @access protected
+ */
protected $exceptions = false;
/////////////////////////////////////////////////
@@ -353,12 +516,55 @@ class PHPMailer {
const STOP_MESSAGE = 0; // message only, continue processing
const STOP_CONTINUE = 1; // message?, likely ok to continue processing
const STOP_CRITICAL = 2; // message, plus full stop, critical error reached
+ const CRLF = "\r\n"; // SMTP RFC specified EOL
/////////////////////////////////////////////////
// METHODS, VARIABLES
/////////////////////////////////////////////////
/**
+ * Calls actual mail() function, but in a safe_mode aware fashion
+ * Also, unless sendmail_path points to sendmail (or something that
+ * claims to be sendmail), don't pass params (not a perfect fix,
+ * but it will do)
+ * @param string $to To
+ * @param string $subject Subject
+ * @param string $body Message Body
+ * @param string $header Additional Header(s)
+ * @param string $params Params
+ * @access private
+ * @return bool
+ */
+ private function mail_passthru($to, $subject, $body, $header, $params) {
+ if ( ini_get('safe_mode') || !($this->UseSendmailOptions) ) {
+ $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($subject)), $body, $header);
+ } else {
+ $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($subject)), $body, $header, $params);
+ }
+ return $rt;
+ }
+
+ /**
+ * Outputs debugging info via user-defined method
+ * @param string $str
+ */
+ protected function edebug($str) {
+ switch ($this->Debugoutput) {
+ case 'error_log':
+ error_log($str);
+ break;
+ case 'html':
+ //Cleans up output a bit for a better looking display that's HTML-safe
+ echo htmlentities(preg_replace('/[\r\n]+/', '', $str), ENT_QUOTES, $this->CharSet)."<br>\n";
+ break;
+ case 'echo':
+ default:
+ //Just echoes exactly what was received
+ echo $str;
+ }
+ }
+
+ /**
* Constructor
* @param boolean $exceptions Should we throw external exceptions?
*/
@@ -367,6 +573,15 @@ class PHPMailer {
}
/**
+ * Destructor
+ */
+ public function __destruct() {
+ if ($this->Mailer == 'smtp') { //Close any open SMTP connection nicely
+ $this->SmtpClose();
+ }
+ }
+
+ /**
* Sets message type to HTML.
* @param bool $ishtml
* @return void
@@ -460,7 +675,7 @@ class PHPMailer {
* @return boolean
*/
public function AddReplyTo($address, $name = '') {
- return $this->AddAnAddress('ReplyTo', $address, $name);
+ return $this->AddAnAddress('Reply-To', $address, $name);
}
/**
@@ -469,29 +684,34 @@ class PHPMailer {
* @param string $kind One of 'to', 'cc', 'bcc', 'ReplyTo'
* @param string $address The email address to send to
* @param string $name
+ * @throws phpmailerException
* @return boolean true on success, false if address already used or invalid in some way
* @access protected
*/
protected function AddAnAddress($kind, $address, $name = '') {
- if (!preg_match('/^(to|cc|bcc|ReplyTo)$/', $kind)) {
+ if (!preg_match('/^(to|cc|bcc|Reply-To)$/', $kind)) {
$this->SetError($this->Lang('Invalid recipient array').': '.$kind);
if ($this->exceptions) {
throw new phpmailerException('Invalid recipient array: ' . $kind);
}
- echo $this->Lang('Invalid recipient array').': '.$kind;
+ if ($this->SMTPDebug) {
+ $this->edebug($this->Lang('Invalid recipient array').': '.$kind);
+ }
return false;
}
$address = trim($address);
$name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
- if (!self::ValidateAddress($address)) {
+ if (!$this->ValidateAddress($address)) {
$this->SetError($this->Lang('invalid_address').': '. $address);
if ($this->exceptions) {
throw new phpmailerException($this->Lang('invalid_address').': '.$address);
}
- echo $this->Lang('invalid_address').': '.$address;
+ if ($this->SMTPDebug) {
+ $this->edebug($this->Lang('invalid_address').': '.$address);
+ }
return false;
}
- if ($kind != 'ReplyTo') {
+ if ($kind != 'Reply-To') {
if (!isset($this->all_recipients[strtolower($address)])) {
array_push($this->$kind, array($address, $name));
$this->all_recipients[strtolower($address)] = true;
@@ -506,29 +726,30 @@ class PHPMailer {
return false;
}
-/**
- * Set the From and FromName properties
- * @param string $address
- * @param string $name
- * @return boolean
- */
- public function SetFrom($address, $name = '', $auto = 1) {
+ /**
+ * Set the From and FromName properties
+ * @param string $address
+ * @param string $name
+ * @param boolean $auto Whether to also set the Sender address, defaults to true
+ * @throws phpmailerException
+ * @return boolean
+ */
+ public function SetFrom($address, $name = '', $auto = true) {
$address = trim($address);
$name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
- if (!self::ValidateAddress($address)) {
+ if (!$this->ValidateAddress($address)) {
$this->SetError($this->Lang('invalid_address').': '. $address);
if ($this->exceptions) {
throw new phpmailerException($this->Lang('invalid_address').': '.$address);
}
- echo $this->Lang('invalid_address').': '.$address;
+ if ($this->SMTPDebug) {
+ $this->edebug($this->Lang('invalid_address').': '.$address);
+ }
return false;
}
$this->From = $address;
$this->FromName = $name;
if ($auto) {
- if (empty($this->ReplyTo)) {
- $this->AddAnAddress('ReplyTo', $address, $name);
- }
if (empty($this->Sender)) {
$this->Sender = $address;
}
@@ -538,25 +759,30 @@ class PHPMailer {
/**
* Check that a string looks roughly like an email address should
- * Static so it can be used without instantiation
- * Tries to use PHP built-in validator in the filter extension (from PHP 5.2), falls back to a reasonably competent regex validator
- * Conforms approximately to RFC2822
- * @link http://www.hexillion.com/samples/#Regex Original pattern found here
+ * Static so it can be used without instantiation, public so people can overload
+ * Conforms to RFC5322: Uses *correct* regex on which FILTER_VALIDATE_EMAIL is
+ * based; So why not use FILTER_VALIDATE_EMAIL? Because it was broken to
+ * not allow a@b type valid addresses :(
+ * @link http://squiloople.com/2009/12/20/email-address-validation/
+ * @copyright regex Copyright Michael Rushton 2009-10 | http://squiloople.com/ | Feel free to use and redistribute this code. But please keep this copyright notice.
* @param string $address The email address to check
* @return boolean
* @static
* @access public
*/
public static function ValidateAddress($address) {
- if (function_exists('filter_var')) { //Introduced in PHP 5.2
- if(filter_var($address, FILTER_VALIDATE_EMAIL) === FALSE) {
- return false;
+ if (defined('PCRE_VERSION')) { //Check this instead of extension_loaded so it works when that function is disabled
+ if (version_compare(PCRE_VERSION, '8.0') >= 0) {
+ return (boolean)preg_match('/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD', $address);
+ } else {
+ //Fall back to an older regex that doesn't need a recent PCRE
+ return (boolean)preg_match('/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD', $address);
+ }
} else {
- return true;
+ //No PCRE! Do something _very_ approximate!
+ //Check the address is 3 chars or longer and contains an @ that's not the first or last char
+ return (strlen($address) >= 3 and strpos($address, '@') >= 1 and strpos($address, '@') != strlen($address) - 1);
}
- } else {
- return preg_match('/^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!\.)){0,61}[a-zA-Z0-9_-]?\.)+[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!$)){0,61}[a-zA-Z0-9_]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/', $address);
- }
}
/////////////////////////////////////////////////
@@ -567,6 +793,7 @@ class PHPMailer {
* Creates message and assigns Mailer. If the message is
* not sent successfully then it returns false. Use the ErrorInfo
* variable to view description of the error.
+ * @throws phpmailerException
* @return bool
*/
public function Send() {
@@ -574,6 +801,7 @@ class PHPMailer {
if(!$this->PreSend()) return false;
return $this->PostSend();
} catch (phpmailerException $e) {
+ $this->mailHeader = '';
$this->SetError($e->getMessage());
if ($this->exceptions) {
throw $e;
@@ -582,8 +810,14 @@ class PHPMailer {
}
}
- protected function PreSend() {
+ /**
+ * Prep mail by constructing all message entities
+ * @throws phpmailerException
+ * @return bool
+ */
+ public function PreSend() {
try {
+ $this->mailHeader = "";
if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
throw new phpmailerException($this->Lang('provide_address'), self::STOP_CRITICAL);
}
@@ -595,22 +829,33 @@ class PHPMailer {
$this->error_count = 0; // reset errors
$this->SetMessageType();
- //Refuse to send an empty message
- if (empty($this->Body)) {
+ //Refuse to send an empty message unless we are specifically allowing it
+ if (!$this->AllowEmpty and empty($this->Body)) {
throw new phpmailerException($this->Lang('empty_message'), self::STOP_CRITICAL);
}
$this->MIMEHeader = $this->CreateHeader();
$this->MIMEBody = $this->CreateBody();
+ // To capture the complete message when using mail(), create
+ // an extra header list which CreateHeader() doesn't fold in
+ if ($this->Mailer == 'mail') {
+ if (count($this->to) > 0) {
+ $this->mailHeader .= $this->AddrAppend("To", $this->to);
+ } else {
+ $this->mailHeader .= $this->HeaderLine("To", "undisclosed-recipients:;");
+ }
+ $this->mailHeader .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader(trim($this->Subject))));
+ }
// digitally sign with DKIM if enabled
- if ($this->DKIM_domain && $this->DKIM_private) {
- $header_dkim = $this->DKIM_Add($this->MIMEHeader, $this->EncodeHeader($this->SecureHeader($this->Subject)), $this->MIMEBody);
+ if (!empty($this->DKIM_domain) && !empty($this->DKIM_private) && !empty($this->DKIM_selector) && !empty($this->DKIM_domain) && file_exists($this->DKIM_private)) {
+ $header_dkim = $this->DKIM_Add($this->MIMEHeader . $this->mailHeader, $this->EncodeHeader($this->SecureHeader($this->Subject)), $this->MIMEBody);
$this->MIMEHeader = str_replace("\r\n", "\n", $header_dkim) . $this->MIMEHeader;
}
return true;
+
} catch (phpmailerException $e) {
$this->SetError($e->getMessage());
if ($this->exceptions) {
@@ -620,7 +865,13 @@ class PHPMailer {
}
}
- protected function PostSend() {
+ /**
+ * Actual Email transport function
+ * Send the email via the selected mechanism
+ * @throws phpmailerException
+ * @return bool
+ */
+ public function PostSend() {
try {
// Choose the mailer and send through it
switch($this->Mailer) {
@@ -628,35 +879,39 @@ class PHPMailer {
return $this->SendmailSend($this->MIMEHeader, $this->MIMEBody);
case 'smtp':
return $this->SmtpSend($this->MIMEHeader, $this->MIMEBody);
+ case 'mail':
+ return $this->MailSend($this->MIMEHeader, $this->MIMEBody);
default:
return $this->MailSend($this->MIMEHeader, $this->MIMEBody);
}
-
} catch (phpmailerException $e) {
$this->SetError($e->getMessage());
if ($this->exceptions) {
throw $e;
}
- echo $e->getMessage()."\n";
- return false;
+ if ($this->SMTPDebug) {
+ $this->edebug($e->getMessage()."\n");
+ }
}
+ return false;
}
/**
* Sends mail using the $Sendmail program.
* @param string $header The message headers
* @param string $body The message body
+ * @throws phpmailerException
* @access protected
* @return bool
*/
protected function SendmailSend($header, $body) {
if ($this->Sender != '') {
- $sendmail = sprintf("%s -oi -f %s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
+ $sendmail = sprintf("%s -oi -f%s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
} else {
$sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail));
}
if ($this->SingleTo === true) {
- foreach ($this->SingleToArray as $key => $val) {
+ foreach ($this->SingleToArray as $val) {
if(!@$mail = popen($sendmail, 'w')) {
throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
}
@@ -692,6 +947,7 @@ class PHPMailer {
* Sends mail using the PHP mail() function.
* @param string $header The message headers
* @param string $body The message body
+ * @throws phpmailerException
* @access protected
* @return bool
*/
@@ -703,40 +959,27 @@ class PHPMailer {
$to = implode(', ', $toArr);
if (empty($this->Sender)) {
- $params = "-oi -f %s";
+ $params = " ";
} else {
- $params = sprintf("-oi -f %s", $this->Sender);
+ $params = sprintf("-f%s", $this->Sender);
}
if ($this->Sender != '' and !ini_get('safe_mode')) {
$old_from = ini_get('sendmail_from');
ini_set('sendmail_from', $this->Sender);
- if ($this->SingleTo === true && count($toArr) > 1) {
- foreach ($toArr as $key => $val) {
- $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
- // implement call back function if it exists
- $isSent = ($rt == 1) ? 1 : 0;
- $this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body);
- }
- } else {
- $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
+ }
+ $rt = false;
+ if ($this->SingleTo === true && count($toArr) > 1) {
+ foreach ($toArr as $val) {
+ $rt = $this->mail_passthru($val, $this->Subject, $body, $header, $params);
// implement call back function if it exists
$isSent = ($rt == 1) ? 1 : 0;
- $this->doCallback($isSent, $to, $this->cc, $this->bcc, $this->Subject, $body);
+ $this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body);
}
} else {
- if ($this->SingleTo === true && count($toArr) > 1) {
- foreach ($toArr as $key => $val) {
- $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
- // implement call back function if it exists
- $isSent = ($rt == 1) ? 1 : 0;
- $this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body);
- }
- } else {
- $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header);
- // implement call back function if it exists
- $isSent = ($rt == 1) ? 1 : 0;
- $this->doCallback($isSent, $to, $this->cc, $this->bcc, $this->Subject, $body);
- }
+ $rt = $this->mail_passthru($to, $this->Subject, $body, $header, $params);
+ // implement call back function if it exists
+ $isSent = ($rt == 1) ? 1 : 0;
+ $this->doCallback($isSent, $to, $this->cc, $this->bcc, $this->Subject, $body);
}
if (isset($old_from)) {
ini_set('sendmail_from', $old_from);
@@ -752,6 +995,7 @@ class PHPMailer {
* Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
* @param string $header The message headers
* @param string $body The message body
+ * @throws phpmailerException
* @uses SMTP
* @access protected
* @return bool
@@ -765,7 +1009,8 @@ class PHPMailer {
}
$smtp_from = ($this->Sender == '') ? $this->From : $this->Sender;
if(!$this->smtp->Mail($smtp_from)) {
- throw new phpmailerException($this->Lang('from_failed') . $smtp_from, self::STOP_CRITICAL);
+ $this->SetError($this->Lang('from_failed') . $smtp_from . ' : ' .implode(',', $this->smtp->getError()));
+ throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL);
}
// Attempt to send attach all recipients
@@ -816,6 +1061,9 @@ class PHPMailer {
}
if($this->SMTPKeepAlive == true) {
$this->smtp->Reset();
+ } else {
+ $this->smtp->Quit();
+ $this->smtp->Close();
}
return true;
}
@@ -823,66 +1071,76 @@ class PHPMailer {
/**
* Initiates a connection to an SMTP server.
* Returns false if the operation failed.
+ * @param array $options An array of options compatible with stream_context_create()
* @uses SMTP
* @access public
+ * @throws phpmailerException
* @return bool
*/
- public function SmtpConnect() {
+ public function SmtpConnect($options = array()) {
if(is_null($this->smtp)) {
- $this->smtp = new SMTP();
+ $this->smtp = new SMTP;
+ }
+
+ //Already connected?
+ if ($this->smtp->Connected()) {
+ return true;
}
+ $this->smtp->Timeout = $this->Timeout;
$this->smtp->do_debug = $this->SMTPDebug;
- $hosts = explode(';', $this->Host);
+ $this->smtp->Debugoutput = $this->Debugoutput;
+ $this->smtp->do_verp = $this->do_verp;
$index = 0;
- $connection = $this->smtp->Connected();
-
- // Retry while there is no connection
- try {
- while($index < count($hosts) && !$connection) {
- $hostinfo = array();
- if (preg_match('/^(.+):([0-9]+)$/', $hosts[$index], $hostinfo)) {
- $host = $hostinfo[1];
- $port = $hostinfo[2];
- } else {
- $host = $hosts[$index];
- $port = $this->Port;
- }
-
- $tls = ($this->SMTPSecure == 'tls');
- $ssl = ($this->SMTPSecure == 'ssl');
-
- if ($this->smtp->Connect(($ssl ? 'ssl://':'').$host, $port, $this->Timeout)) {
+ $tls = ($this->SMTPSecure == 'tls');
+ $ssl = ($this->SMTPSecure == 'ssl');
+ $hosts = explode(';', $this->Host);
+ $lastexception = null;
- $hello = ($this->Helo != '' ? $this->Helo : $this->ServerHostname());
+ foreach ($hosts as $hostentry) {
+ $hostinfo = array();
+ $host = $hostentry;
+ $port = $this->Port;
+ if (preg_match('/^(.+):([0-9]+)$/', $hostentry, $hostinfo)) { //If $hostentry contains 'address:port', override default
+ $host = $hostinfo[1];
+ $port = $hostinfo[2];
+ }
+ if ($this->smtp->Connect(($ssl ? 'ssl://':'').$host, $port, $this->Timeout, $options)) {
+ try {
+ if ($this->Helo) {
+ $hello = $this->Helo;
+ } else {
+ $hello = $this->ServerHostname();
+ }
$this->smtp->Hello($hello);
if ($tls) {
if (!$this->smtp->StartTLS()) {
- throw new phpmailerException($this->Lang('tls'));
+ throw new phpmailerException($this->Lang('connect_host'));
}
-
//We must resend HELO after tls negotiation
$this->smtp->Hello($hello);
}
-
- $connection = true;
if ($this->SMTPAuth) {
- if (!$this->smtp->Authenticate($this->Username, $this->Password)) {
+ if (!$this->smtp->Authenticate($this->Username, $this->Password, $this->AuthType, $this->Realm, $this->Workstation)) {
throw new phpmailerException($this->Lang('authenticate'));
}
}
- }
- $index++;
- if (!$connection) {
- throw new phpmailerException($this->Lang('connect_host'));
+ return true;
+ } catch (phpmailerException $e) {
+ $lastexception = $e;
+ //We must have connected, but then failed TLS or Auth, so close connection nicely
+ $this->smtp->Quit();
}
}
- } catch (phpmailerException $e) {
- $this->smtp->Reset();
- throw $e;
}
- return true;
+ //If we get here, all connection attempts have failed, so close connection hard
+ $this->smtp->Close();
+ //As we've caught all exceptions, just report whatever the last one was
+ if ($this->exceptions and !is_null($lastexception)) {
+ throw $lastexception;
+ }
+ return false;
}
/**
@@ -890,7 +1148,7 @@ class PHPMailer {
* @return void
*/
public function SmtpClose() {
- if(!is_null($this->smtp)) {
+ if ($this->smtp !== null) {
if($this->smtp->Connected()) {
$this->smtp->Quit();
$this->smtp->Close();
@@ -899,32 +1157,34 @@ class PHPMailer {
}
/**
- * Sets the language for all class error messages.
- * Returns false if it cannot load the language file. The default language is English.
- * @param string $langcode ISO 639-1 2-character language code (e.g. Portuguese: "br")
- * @param string $lang_path Path to the language file directory
- * @access public
- */
+ * Sets the language for all class error messages.
+ * Returns false if it cannot load the language file. The default language is English.
+ * @param string $langcode ISO 639-1 2-character language code (e.g. Portuguese: "br")
+ * @param string $lang_path Path to the language file directory
+ * @return bool
+ * @access public
+ */
function SetLanguage($langcode = 'en', $lang_path = 'language/') {
//Define full set of translatable strings
$PHPMAILER_LANG = array(
- 'provide_address' => 'You must provide at least one recipient email address.',
+ 'authenticate' => 'SMTP Error: Could not authenticate.',
+ 'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
+ 'data_not_accepted' => 'SMTP Error: Data not accepted.',
+ 'empty_message' => 'Message body empty',
+ 'encoding' => 'Unknown encoding: ',
+ 'execute' => 'Could not execute: ',
+ 'file_access' => 'Could not access file: ',
+ 'file_open' => 'File Error: Could not open file: ',
+ 'from_failed' => 'The following From address failed: ',
+ 'instantiate' => 'Could not instantiate mail function.',
+ 'invalid_address' => 'Invalid address',
'mailer_not_supported' => ' mailer is not supported.',
- 'execute' => 'Could not execute: ',
- 'instantiate' => 'Could not instantiate mail function.',
- 'authenticate' => 'SMTP Error: Could not authenticate.',
- 'from_failed' => 'The following From address failed: ',
- 'recipients_failed' => 'SMTP Error: The following recipients failed: ',
- 'data_not_accepted' => 'SMTP Error: Data not accepted.',
- 'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
- 'file_access' => 'Could not access file: ',
- 'file_open' => 'File Error: Could not open file: ',
- 'encoding' => 'Unknown encoding: ',
- 'signing' => 'Signing Error: ',
- 'smtp_error' => 'SMTP server error: ',
- 'empty_message' => 'Message body empty',
- 'invalid_address' => 'Invalid address',
- 'variable_set' => 'Cannot set or reset variable: '
+ 'provide_address' => 'You must provide at least one recipient email address.',
+ 'recipients_failed' => 'SMTP Error: The following recipients failed: ',
+ 'signing' => 'Signing Error: ',
+ 'smtp_connect_failed' => 'SMTP Connect() failed.',
+ 'smtp_error' => 'SMTP server error: ',
+ 'variable_set' => 'Cannot set or reset variable: '
);
//Overwrite language-specific strings. This way we'll never have missing translations - no more "language string failed to load"!
$l = true;
@@ -950,6 +1210,8 @@ class PHPMailer {
/**
* Creates recipient headers.
* @access public
+ * @param string $type
+ * @param array $addr
* @return string
*/
public function AddrAppend($type, $addr) {
@@ -967,6 +1229,7 @@ class PHPMailer {
/**
* Formats an address correctly.
* @access public
+ * @param string $addr
* @return string
*/
public function AddrFormat($addr) {
@@ -992,13 +1255,15 @@ class PHPMailer {
// If utf-8 encoding is used, we will need to make sure we don't
// split multibyte characters when we wrap
$is_utf8 = (strtolower($this->CharSet) == "utf-8");
+ $lelen = strlen($this->LE);
+ $crlflen = strlen(self::CRLF);
$message = $this->FixEOL($message);
- if (substr($message, -1) == $this->LE) {
- $message = substr($message, 0, -1);
+ if (substr($message, -$lelen) == $this->LE) {
+ $message = substr($message, 0, -$lelen);
}
- $line = explode($this->LE, $message);
+ $line = explode($this->LE, $message); // Magic. We know FixEOL uses $LE
$message = '';
for ($i = 0 ;$i < count($line); $i++) {
$line_part = explode(' ', $line[$i]);
@@ -1006,7 +1271,7 @@ class PHPMailer {
for ($e = 0; $e<count($line_part); $e++) {
$word = $line_part[$e];
if ($qp_mode and (strlen($word) > $length)) {
- $space_left = $length - strlen($buf) - 1;
+ $space_left = $length - strlen($buf) - $crlflen;
if ($e != 0) {
if ($space_left > 20) {
$len = $space_left;
@@ -1020,13 +1285,16 @@ class PHPMailer {
$part = substr($word, 0, $len);
$word = substr($word, $len);
$buf .= ' ' . $part;
- $message .= $buf . sprintf("=%s", $this->LE);
+ $message .= $buf . sprintf("=%s", self::CRLF);
} else {
$message .= $buf . $soft_break;
}
$buf = '';
}
while (strlen($word) > 0) {
+ if ($length <= 0) {
+ break;
+ }
$len = $length;
if ($is_utf8) {
$len = $this->UTF8CharBoundary($word, $len);
@@ -1039,7 +1307,7 @@ class PHPMailer {
$word = substr($word, $len);
if (strlen($word) > 0) {
- $message .= $part . sprintf("=%s", $this->LE);
+ $message .= $part . sprintf("=%s", self::CRLF);
} else {
$buf = $part;
}
@@ -1054,7 +1322,7 @@ class PHPMailer {
}
}
}
- $message .= $buf . $this->LE;
+ $message .= $buf . self::CRLF;
}
return $message;
@@ -1139,11 +1407,18 @@ class PHPMailer {
$this->boundary[2] = 'b2_' . $uniq_id;
$this->boundary[3] = 'b3_' . $uniq_id;
- $result .= $this->HeaderLine('Date', self::RFCDate());
- if($this->Sender == '') {
- $result .= $this->HeaderLine('Return-Path', trim($this->From));
+ if ($this->MessageDate == '') {
+ $result .= $this->HeaderLine('Date', self::RFCDate());
+ } else {
+ $result .= $this->HeaderLine('Date', $this->MessageDate);
+ }
+
+ if ($this->ReturnPath) {
+ $result .= $this->HeaderLine('Return-Path', '<'.trim($this->ReturnPath).'>');
+ } elseif ($this->Sender == '') {
+ $result .= $this->HeaderLine('Return-Path', '<'.trim($this->From).'>');
} else {
- $result .= $this->HeaderLine('Return-Path', trim($this->Sender));
+ $result .= $this->HeaderLine('Return-Path', '<'.trim($this->Sender).'>');
}
// To be created automatically by mail()
@@ -1177,7 +1452,7 @@ class PHPMailer {
}
if(count($this->ReplyTo) > 0) {
- $result .= $this->AddrAppend('Reply-to', $this->ReplyTo);
+ $result .= $this->AddrAppend('Reply-To', $this->ReplyTo);
}
// mail() sets the subject itself
@@ -1191,10 +1466,13 @@ class PHPMailer {
$result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE);
}
$result .= $this->HeaderLine('X-Priority', $this->Priority);
- if($this->XMailer) {
- $result .= $this->HeaderLine('X-Mailer', $this->XMailer);
+ if ($this->XMailer == '') {
+ $result .= $this->HeaderLine('X-Mailer', 'PHPMailer '.$this->Version.' (https://github.com/PHPMailer/PHPMailer/)');
} else {
- $result .= $this->HeaderLine('X-Mailer', 'PHPMailer '.$this->Version.' (http://code.google.com/a/apache-extras.org/p/phpmailer/)');
+ $myXmailer = trim($this->XMailer);
+ if ($myXmailer) {
+ $result .= $this->HeaderLine('X-Mailer', $myXmailer);
+ }
}
if($this->ConfirmReadingTo != '') {
@@ -1221,76 +1499,88 @@ class PHPMailer {
public function GetMailMIME() {
$result = '';
switch($this->message_type) {
- case 'plain':
- $result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding);
- $result .= $this->TextLine('Content-Type: '.$this->ContentType.'; charset="'.$this->CharSet.'"');
- break;
case 'inline':
$result .= $this->HeaderLine('Content-Type', 'multipart/related;');
- $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
+ $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1].'"');
break;
case 'attach':
case 'inline_attach':
case 'alt_attach':
case 'alt_inline_attach':
$result .= $this->HeaderLine('Content-Type', 'multipart/mixed;');
- $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
+ $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1].'"');
break;
case 'alt':
case 'alt_inline':
$result .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
- $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
+ $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1].'"');
break;
+ default:
+ // Catches case 'plain': and case '':
+ $result .= $this->TextLine('Content-Type: '.$this->ContentType.'; charset='.$this->CharSet);
+ break;
+ }
+ //RFC1341 part 5 says 7bit is assumed if not specified
+ if ($this->Encoding != '7bit') {
+ $result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding);
}
if($this->Mailer != 'mail') {
- $result .= $this->LE.$this->LE;
+ $result .= $this->LE;
}
return $result;
}
/**
+ * Returns the MIME message (headers and body). Only really valid post PreSend().
+ * @access public
+ * @return string
+ */
+ public function GetSentMIMEMessage() {
+ return $this->MIMEHeader . $this->mailHeader . self::CRLF . $this->MIMEBody;
+ }
+
+
+ /**
* Assembles the message body. Returns an empty string on failure.
* @access public
+ * @throws phpmailerException
* @return string The assembled message body
*/
public function CreateBody() {
$body = '';
if ($this->sign_key_file) {
- $body .= $this->GetMailMIME();
+ $body .= $this->GetMailMIME().$this->LE;
}
$this->SetWordWrap();
switch($this->message_type) {
- case 'plain':
- $body .= $this->EncodeString($this->Body, $this->Encoding);
- break;
case 'inline':
$body .= $this->GetBoundary($this->boundary[1], '', '', '');
$body .= $this->EncodeString($this->Body, $this->Encoding);
$body .= $this->LE.$this->LE;
- $body .= $this->AttachAll("inline", $this->boundary[1]);
+ $body .= $this->AttachAll('inline', $this->boundary[1]);
break;
case 'attach':
$body .= $this->GetBoundary($this->boundary[1], '', '', '');
$body .= $this->EncodeString($this->Body, $this->Encoding);
$body .= $this->LE.$this->LE;
- $body .= $this->AttachAll("attachment", $this->boundary[1]);
+ $body .= $this->AttachAll('attachment', $this->boundary[1]);
break;
case 'inline_attach':
- $body .= $this->TextLine("--" . $this->boundary[1]);
+ $body .= $this->TextLine('--' . $this->boundary[1]);
$body .= $this->HeaderLine('Content-Type', 'multipart/related;');
- $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2] . '"');
+ $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2].'"');
$body .= $this->LE;
$body .= $this->GetBoundary($this->boundary[2], '', '', '');
$body .= $this->EncodeString($this->Body, $this->Encoding);
$body .= $this->LE.$this->LE;
- $body .= $this->AttachAll("inline", $this->boundary[2]);
+ $body .= $this->AttachAll('inline', $this->boundary[2]);
$body .= $this->LE;
- $body .= $this->AttachAll("attachment", $this->boundary[1]);
+ $body .= $this->AttachAll('attachment', $this->boundary[1]);
break;
case 'alt':
$body .= $this->GetBoundary($this->boundary[1], '', 'text/plain', '');
@@ -1299,27 +1589,32 @@ class PHPMailer {
$body .= $this->GetBoundary($this->boundary[1], '', 'text/html', '');
$body .= $this->EncodeString($this->Body, $this->Encoding);
$body .= $this->LE.$this->LE;
+ if(!empty($this->Ical)) {
+ $body .= $this->GetBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', '');
+ $body .= $this->EncodeString($this->Ical, $this->Encoding);
+ $body .= $this->LE.$this->LE;
+ }
$body .= $this->EndBoundary($this->boundary[1]);
break;
case 'alt_inline':
$body .= $this->GetBoundary($this->boundary[1], '', 'text/plain', '');
$body .= $this->EncodeString($this->AltBody, $this->Encoding);
$body .= $this->LE.$this->LE;
- $body .= $this->TextLine("--" . $this->boundary[1]);
+ $body .= $this->TextLine('--' . $this->boundary[1]);
$body .= $this->HeaderLine('Content-Type', 'multipart/related;');
- $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2] . '"');
+ $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2].'"');
$body .= $this->LE;
$body .= $this->GetBoundary($this->boundary[2], '', 'text/html', '');
$body .= $this->EncodeString($this->Body, $this->Encoding);
$body .= $this->LE.$this->LE;
- $body .= $this->AttachAll("inline", $this->boundary[2]);
+ $body .= $this->AttachAll('inline', $this->boundary[2]);
$body .= $this->LE;
$body .= $this->EndBoundary($this->boundary[1]);
break;
case 'alt_attach':
- $body .= $this->TextLine("--" . $this->boundary[1]);
+ $body .= $this->TextLine('--' . $this->boundary[1]);
$body .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
- $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2] . '"');
+ $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2].'"');
$body .= $this->LE;
$body .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '');
$body .= $this->EncodeString($this->AltBody, $this->Encoding);
@@ -1329,28 +1624,32 @@ class PHPMailer {
$body .= $this->LE.$this->LE;
$body .= $this->EndBoundary($this->boundary[2]);
$body .= $this->LE;
- $body .= $this->AttachAll("attachment", $this->boundary[1]);
+ $body .= $this->AttachAll('attachment', $this->boundary[1]);
break;
case 'alt_inline_attach':
- $body .= $this->TextLine("--" . $this->boundary[1]);
+ $body .= $this->TextLine('--' . $this->boundary[1]);
$body .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
- $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2] . '"');
+ $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2].'"');
$body .= $this->LE;
$body .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '');
$body .= $this->EncodeString($this->AltBody, $this->Encoding);
$body .= $this->LE.$this->LE;
- $body .= $this->TextLine("--" . $this->boundary[2]);
+ $body .= $this->TextLine('--' . $this->boundary[2]);
$body .= $this->HeaderLine('Content-Type', 'multipart/related;');
- $body .= $this->TextLine("\tboundary=\"" . $this->boundary[3] . '"');
+ $body .= $this->TextLine("\tboundary=\"" . $this->boundary[3].'"');
$body .= $this->LE;
$body .= $this->GetBoundary($this->boundary[3], '', 'text/html', '');
$body .= $this->EncodeString($this->Body, $this->Encoding);
$body .= $this->LE.$this->LE;
- $body .= $this->AttachAll("inline", $this->boundary[3]);
+ $body .= $this->AttachAll('inline', $this->boundary[3]);
$body .= $this->LE;
$body .= $this->EndBoundary($this->boundary[2]);
$body .= $this->LE;
- $body .= $this->AttachAll("attachment", $this->boundary[1]);
+ $body .= $this->AttachAll('attachment', $this->boundary[1]);
+ break;
+ default:
+ // catch case 'plain' and case ''
+ $body .= $this->EncodeString($this->Body, $this->Encoding);
break;
}
@@ -1358,17 +1657,20 @@ class PHPMailer {
$body = '';
} elseif ($this->sign_key_file) {
try {
- $file = tempnam('', 'mail');
+ if (!defined('PKCS7_TEXT')) {
+ throw new phpmailerException($this->Lang('signing').' OpenSSL extension missing.');
+ }
+ $file = tempnam(sys_get_temp_dir(), 'mail');
file_put_contents($file, $body); //TODO check this worked
- $signed = tempnam("", "signed");
- if (@openssl_pkcs7_sign($file, $signed, "file://".$this->sign_cert_file, array("file://".$this->sign_key_file, $this->sign_key_pass), NULL)) {
+ $signed = tempnam(sys_get_temp_dir(), 'signed');
+ if (@openssl_pkcs7_sign($file, $signed, 'file://'.realpath($this->sign_cert_file), array('file://'.realpath($this->sign_key_file), $this->sign_key_pass), null)) {
@unlink($file);
- @unlink($signed);
$body = file_get_contents($signed);
+ @unlink($signed);
} else {
@unlink($file);
@unlink($signed);
- throw new phpmailerException($this->Lang("signing").openssl_error_string());
+ throw new phpmailerException($this->Lang('signing').openssl_error_string());
}
} catch (phpmailerException $e) {
$body = '';
@@ -1377,13 +1679,16 @@ class PHPMailer {
}
}
}
-
return $body;
}
/**
* Returns the start of a message boundary.
* @access protected
+ * @param string $boundary
+ * @param string $charSet
+ * @param string $contentType
+ * @param string $encoding
* @return string
*/
protected function GetBoundary($boundary, $charSet, $contentType, $encoding) {
@@ -1398,7 +1703,7 @@ class PHPMailer {
$encoding = $this->Encoding;
}
$result .= $this->TextLine('--' . $boundary);
- $result .= sprintf("Content-Type: %s; charset=\"%s\"", $contentType, $charSet);
+ $result .= sprintf("Content-Type: %s; charset=%s", $contentType, $charSet);
$result .= $this->LE;
$result .= $this->HeaderLine('Content-Transfer-Encoding', $encoding);
$result .= $this->LE;
@@ -1409,6 +1714,7 @@ class PHPMailer {
/**
* Returns the end of a message boundary.
* @access protected
+ * @param string $boundary
* @return string
*/
protected function EndBoundary($boundary) {
@@ -1430,8 +1736,10 @@ class PHPMailer {
}
/**
- * Returns a formatted header line.
+ * Returns a formatted header line.
* @access public
+ * @param string $name
+ * @param string $value
* @return string
*/
public function HeaderLine($name, $value) {
@@ -1441,6 +1749,7 @@ class PHPMailer {
/**
* Returns a formatted mail line.
* @access public
+ * @param string $value
* @return string
*/
public function TextLine($value) {
@@ -1459,13 +1768,20 @@ class PHPMailer {
* @param string $name Overrides the attachment name.
* @param string $encoding File encoding (see $Encoding).
* @param string $type File extension (MIME) type.
+ * @throws phpmailerException
* @return bool
*/
- public function AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
+ public function AddAttachment($path, $name = '', $encoding = 'base64', $type = '') {
try {
if ( !@is_file($path) ) {
throw new phpmailerException($this->Lang('file_access') . $path, self::STOP_CONTINUE);
}
+
+ //If a MIME type is not specified, try to work it out from the file name
+ if ($type == '') {
+ $type = self::filenameToType($path);
+ }
+
$filename = basename($path);
if ( $name == '' ) {
$name = $filename;
@@ -1487,10 +1803,10 @@ class PHPMailer {
if ($this->exceptions) {
throw $e;
}
- echo $e->getMessage()."\n";
- if ( $e->getCode() == self::STOP_CRITICAL ) {
- return false;
+ if ($this->SMTPDebug) {
+ $this->edebug($e->getMessage()."\n");
}
+ return false;
}
return true;
}
@@ -1507,6 +1823,8 @@ class PHPMailer {
* Attaches all fs, string, and binary attachments to the message.
* Returns an empty string on failure.
* @access protected
+ * @param string $disposition_type
+ * @param string $boundary
* @return string
*/
protected function AttachAll($disposition_type, $boundary) {
@@ -1520,6 +1838,8 @@ class PHPMailer {
// CHECK IF IT IS A VALID DISPOSITION_FILTER
if($attachment[6] == $disposition_type) {
// Check for string attachment
+ $string = '';
+ $path = '';
$bString = $attachment[5];
if ($bString) {
$string = $attachment[0];
@@ -1547,7 +1867,13 @@ class PHPMailer {
$mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE);
}
- $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", $disposition, $this->EncodeHeader($this->SecureHeader($name)), $this->LE.$this->LE);
+ //If a filename contains any of these chars, it should be quoted, but not otherwise: RFC2183 & RFC2045 5.1
+ //Fixes a warning in IETF's msglint MIME checker
+ if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $name)) {
+ $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", $disposition, $this->EncodeHeader($this->SecureHeader($name)), $this->LE.$this->LE);
+ } else {
+ $mime[] = sprintf("Content-Disposition: %s; filename=%s%s", $disposition, $this->EncodeHeader($this->SecureHeader($name)), $this->LE.$this->LE);
+ }
// Encode as string attachment
if($bString) {
@@ -1576,6 +1902,7 @@ class PHPMailer {
* Returns an empty string on failure.
* @param string $path The full path to the file
* @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
+ * @throws phpmailerException
* @see EncodeFile()
* @access protected
* @return string
@@ -1585,19 +1912,22 @@ class PHPMailer {
if (!is_readable($path)) {
throw new phpmailerException($this->Lang('file_open') . $path, self::STOP_CONTINUE);
}
- if (function_exists('get_magic_quotes')) {
- function get_magic_quotes() {
- return false;
+ $magic_quotes = get_magic_quotes_runtime();
+ if ($magic_quotes) {
+ if (version_compare(PHP_VERSION, '5.3.0', '<')) {
+ set_magic_quotes_runtime(0);
+ } else {
+ ini_set('magic_quotes_runtime', 0);
}
}
- if (version_compare(PHP_VERSION, '5.3.0', '<')) {
- $magic_quotes = get_magic_quotes_runtime();
- set_magic_quotes_runtime(0);
- }
$file_buffer = file_get_contents($path);
$file_buffer = $this->EncodeString($file_buffer, $encoding);
- if (version_compare(PHP_VERSION, '5.3.0', '<')) {
- set_magic_quotes_runtime($magic_quotes);
+ if ($magic_quotes) {
+ if (version_compare(PHP_VERSION, '5.3.0', '<')) {
+ set_magic_quotes_runtime($magic_quotes);
+ } else {
+ ini_set('magic_quotes_runtime', $magic_quotes);
+ }
}
return $file_buffer;
} catch (Exception $e) {
@@ -1643,6 +1973,8 @@ class PHPMailer {
/**
* Encode a header string to best (shortest) of Q, B, quoted or none.
* @access public
+ * @param string $str
+ * @param string $position
* @return string
*/
public function EncodeHeader($str, $position = 'text') {
@@ -1670,18 +2002,18 @@ class PHPMailer {
break;
}
- if ($x == 0) {
+ if ($x == 0) { //There are no chars that need encoding
return ($str);
}
$maxlen = 75 - 7 - strlen($this->CharSet);
// Try to select the encoding which should produce the shortest output
- if (strlen($str)/3 < $x) {
+ if ($x > strlen($str)/3) { //More than a third of the content will need encoding, so B encoding will be most efficient
$encoding = 'B';
if (function_exists('mb_strlen') && $this->HasMultiBytes($str)) {
// Use a custom function which correctly encodes and wraps long
// multibyte strings without breaking lines within a character
- $encoded = $this->Base64EncodeWrapMB($str);
+ $encoded = $this->Base64EncodeWrapMB($str, "\n");
} else {
$encoded = base64_encode($str);
$maxlen -= $maxlen % 4;
@@ -1691,7 +2023,7 @@ class PHPMailer {
$encoding = 'Q';
$encoded = $this->EncodeQ($str, $position);
$encoded = $this->WrapText($encoded, $maxlen, true);
- $encoded = str_replace('='.$this->LE, "\n", trim($encoded));
+ $encoded = str_replace('='.self::CRLF, "\n", trim($encoded));
}
$encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded);
@@ -1720,12 +2052,16 @@ class PHPMailer {
* Adapted from a function by paravoid at http://uk.php.net/manual/en/function.mb-encode-mimeheader.php
* @access public
* @param string $str multi-byte text to wrap encode
+ * @param string $lf string to use as linefeed/end-of-line
* @return string
*/
- public function Base64EncodeWrapMB($str) {
+ public function Base64EncodeWrapMB($str, $lf=null) {
$start = "=?".$this->CharSet."?B?";
$end = "?=";
$encoded = "";
+ if ($lf === null) {
+ $lf = $this->LE;
+ }
$mb_length = mb_strlen($str, $this->CharSet);
// Each line must have length <= 75, including $start and $end
@@ -1746,94 +2082,43 @@ class PHPMailer {
}
while (strlen($chunk) > $length);
- $encoded .= $chunk . $this->LE;
+ $encoded .= $chunk . $lf;
}
// Chomp the last linefeed
- $encoded = substr($encoded, 0, -strlen($this->LE));
+ $encoded = substr($encoded, 0, -strlen($lf));
return $encoded;
}
/**
- * Encode string to quoted-printable.
- * Only uses standard PHP, slow, but will always work
- * @access public
- * @param string $string the text to encode
- * @param integer $line_max Number of chars allowed on a line before wrapping
- * @return string
- */
- public function EncodeQPphp( $input = '', $line_max = 76, $space_conv = false) {
- $hex = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
- $lines = preg_split('/(?:\r\n|\r|\n)/', $input);
- $eol = "\r\n";
- $escape = '=';
- $output = '';
- while( list(, $line) = each($lines) ) {
- $linlen = strlen($line);
- $newline = '';
- for($i = 0; $i < $linlen; $i++) {
- $c = substr( $line, $i, 1 );
- $dec = ord( $c );
- if ( ( $i == 0 ) && ( $dec == 46 ) ) { // convert first point in the line into =2E
- $c = '=2E';
- }
- if ( $dec == 32 ) {
- if ( $i == ( $linlen - 1 ) ) { // convert space at eol only
- $c = '=20';
- } else if ( $space_conv ) {
- $c = '=20';
- }
- } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required
- $h2 = floor($dec/16);
- $h1 = floor($dec%16);
- $c = $escape.$hex[$h2].$hex[$h1];
- }
- if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted
- $output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay
- $newline = '';
- // check if newline first character will be point or not
- if ( $dec == 46 ) {
- $c = '=2E';
- }
- }
- $newline .= $c;
- } // end of for
- $output .= $newline.$eol;
- } // end of while
- return $output;
- }
-
- /**
- * Encode string to RFC2045 (6.7) quoted-printable format
- * Uses a PHP5 stream filter to do the encoding about 64x faster than the old version
- * Also results in same content as you started with after decoding
- * @see EncodeQPphp()
- * @access public
- * @param string $string the text to encode
- * @param integer $line_max Number of chars allowed on a line before wrapping
- * @param boolean $space_conv Dummy param for compatibility with existing EncodeQP function
- * @return string
- * @author Marcus Bointon
- */
- public function EncodeQP($string, $line_max = 76, $space_conv = false) {
+ * Encode string to RFC2045 (6.7) quoted-printable format
+ * @access public
+ * @param string $string The text to encode
+ * @param integer $line_max Number of chars allowed on a line before wrapping
+ * @return string
+ * @link PHP version adapted from http://www.php.net/manual/en/function.quoted-printable-decode.php#89417
+ */
+ public function EncodeQP($string, $line_max = 76) {
if (function_exists('quoted_printable_encode')) { //Use native function if it's available (>= PHP5.3)
return quoted_printable_encode($string);
}
- $filters = stream_get_filters();
- if (!in_array('convert.*', $filters)) { //Got convert stream filter?
- return $this->EncodeQPphp($string, $line_max, $space_conv); //Fall back to old implementation
- }
- $fp = fopen('php://temp/', 'r+');
- $string = preg_replace('/\r\n?/', $this->LE, $string); //Normalise line breaks
- $params = array('line-length' => $line_max, 'line-break-chars' => $this->LE);
- $s = stream_filter_append($fp, 'convert.quoted-printable-encode', STREAM_FILTER_READ, $params);
- fputs($fp, $string);
- rewind($fp);
- $out = stream_get_contents($fp);
- stream_filter_remove($s);
- $out = preg_replace('/^\./m', '=2E', $out); //Encode . if it is first char on a line, workaround for bug in Exchange
- fclose($fp);
- return $out;
+ //Fall back to a pure PHP implementation
+ $string = str_replace(array('%20', '%0D%0A.', '%0D%0A', '%'), array(' ', "\r\n=2E", "\r\n", '='), rawurlencode($string));
+ $string = preg_replace('/[^\r\n]{'.($line_max - 3).'}[^=\r\n]{2}/', "$0=\r\n", $string);
+ return $string;
+ }
+
+ /**
+ * Wrapper to preserve BC for old QP encoding function that was removed
+ * @see EncodeQP()
+ * @access public
+ * @param string $string
+ * @param integer $line_max
+ * @param bool $space_conv
+ * @return string
+ */
+ public function EncodeQPphp($string, $line_max = 76, $space_conv = false) {
+ return $this->EncodeQP($string, $line_max);
}
/**
@@ -1845,29 +2130,37 @@ class PHPMailer {
* @return string
*/
public function EncodeQ($str, $position = 'text') {
- // There should not be any EOL in the string
- $encoded = preg_replace('/[\r\n]*/', '', $str);
-
+ //There should not be any EOL in the string
+ $pattern = '';
+ $encoded = str_replace(array("\r", "\n"), '', $str);
switch (strtolower($position)) {
case 'phrase':
- $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
+ $pattern = '^A-Za-z0-9!*+\/ -';
break;
+
case 'comment':
- $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
+ $pattern = '\(\)"';
+ //note that we don't break here!
+ //for this reason we build the $pattern without including delimiters and []
+
case 'text':
default:
- // Replace every high ascii, control =, ? and _ characters
- //TODO using /e (equivalent to eval()) is probably not a good idea
- $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e',
- "'='.sprintf('%02X', ord(stripslashes('\\1')))", $encoded);
+ //Replace every high ascii, control =, ? and _ characters
+ //We put \075 (=) as first value to make sure it's the first one in being converted, preventing double encode
+ $pattern = '\075\000-\011\013\014\016-\037\077\137\177-\377' . $pattern;
break;
}
- // Replace every spaces to _ (more readable than =20)
- $encoded = str_replace(' ', '_', $encoded);
+ if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
+ foreach (array_unique($matches[0]) as $char) {
+ $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded);
+ }
+ }
+
+ //Replace every spaces to _ (more readable than =20)
+ return str_replace(' ', '_', $encoded);
+}
- return $encoded;
- }
/**
* Adds a string or binary attachment (non-filesystem) to the list.
@@ -1879,7 +2172,11 @@ class PHPMailer {
* @param string $type File extension (MIME) type.
* @return void
*/
- public function AddStringAttachment($string, $filename, $encoding = 'base64', $type = 'application/octet-stream') {
+ public function AddStringAttachment($string, $filename, $encoding = 'base64', $type = '') {
+ //If a MIME type is not specified, try to work it out from the file name
+ if ($type == '') {
+ $type = self::filenameToType($filename);
+ }
// Append to $attachment array
$this->attachment[] = array(
0 => $string,
@@ -1894,25 +2191,27 @@ class PHPMailer {
}
/**
- * Adds an embedded attachment. This can include images, sounds, and
- * just about any other document. Make sure to set the $type to an
- * image type. For JPEG images use "image/jpeg" and for GIF images
- * use "image/gif".
+ * Add an embedded attachment from a file.
+ * This can include images, sounds, and just about any other document type.
* @param string $path Path to the attachment.
- * @param string $cid Content ID of the attachment. Use this to identify
- * the Id for accessing the image in an HTML form.
+ * @param string $cid Content ID of the attachment; Use this to reference
+ * the content when using an embedded image in HTML.
* @param string $name Overrides the attachment name.
* @param string $encoding File encoding (see $Encoding).
- * @param string $type File extension (MIME) type.
- * @return bool
+ * @param string $type File MIME type.
+ * @return bool True on successfully adding an attachment
*/
- public function AddEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
-
+ public function AddEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '') {
if ( !@is_file($path) ) {
$this->SetError($this->Lang('file_access') . $path);
return false;
}
+ //If a MIME type is not specified, try to work it out from the file name
+ if ($type == '') {
+ $type = self::filenameToType($path);
+ }
+
$filename = basename($path);
if ( $name == '' ) {
$name = $filename;
@@ -1929,22 +2228,41 @@ class PHPMailer {
6 => 'inline',
7 => $cid
);
-
return true;
}
- public function AddStringEmbeddedImage($string, $cid, $filename = '', $encoding = 'base64', $type = 'application/octet-stream') {
+
+ /**
+ * Add an embedded stringified attachment.
+ * This can include images, sounds, and just about any other document type.
+ * Be sure to set the $type to an image type for images:
+ * JPEG images use 'image/jpeg', GIF uses 'image/gif', PNG uses 'image/png'.
+ * @param string $string The attachment binary data.
+ * @param string $cid Content ID of the attachment; Use this to reference
+ * the content when using an embedded image in HTML.
+ * @param string $name
+ * @param string $encoding File encoding (see $Encoding).
+ * @param string $type MIME type.
+ * @return bool True on successfully adding an attachment
+ */
+ public function AddStringEmbeddedImage($string, $cid, $name = '', $encoding = 'base64', $type = '') {
+ //If a MIME type is not specified, try to work it out from the name
+ if ($type == '') {
+ $type = self::filenameToType($name);
+ }
+
// Append to $attachment array
$this->attachment[] = array(
0 => $string,
- 1 => $filename,
- 2 => basename($filename),
+ 1 => $name,
+ 2 => $name,
3 => $encoding,
4 => $type,
5 => true, // isStringAttachment
6 => 'inline',
7 => $cid
);
+ return true;
}
/**
@@ -1961,6 +2279,10 @@ class PHPMailer {
return false;
}
+ /**
+ * Returns true if an attachment (non-inline) is present.
+ * @return bool
+ */
public function AttachmentExists() {
foreach($this->attachment as $attachment) {
if ($attachment[6] == 'attachment') {
@@ -1970,8 +2292,12 @@ class PHPMailer {
return false;
}
+ /**
+ * Does this message have an alternative body set?
+ * @return bool
+ */
public function AlternativeExists() {
- return strlen($this->AltBody)>0;
+ return !empty($this->AltBody);
}
/////////////////////////////////////////////////
@@ -2055,6 +2381,7 @@ class PHPMailer {
/**
* Adds the error message to the error container.
* @access protected
+ * @param string $msg
* @return void
*/
protected function SetError($msg) {
@@ -2075,13 +2402,10 @@ class PHPMailer {
* @static
*/
public static function RFCDate() {
- $tz = date('Z');
- $tzs = ($tz < 0) ? '-' : '+';
- $tz = abs($tz);
- $tz = (int)($tz/3600)*100 + ($tz%3600)/60;
- $result = sprintf("%s %s%04d", date('D, j M Y H:i:s'), $tzs, $tz);
-
- return $result;
+ //Set the time zone to whatever the default is to avoid 500 errors
+ //Will default to UTC if it's not set properly in php.ini
+ date_default_timezone_set(@date_default_timezone_get());
+ return date('D, j M Y H:i:s O');
}
/**
@@ -2104,6 +2428,7 @@ class PHPMailer {
/**
* Returns a message in the appropriate language.
* @access protected
+ * @param string $key
* @return string
*/
protected function Lang($key) {
@@ -2128,84 +2453,121 @@ class PHPMailer {
}
/**
- * Changes every end of line from CR or LF to CRLF.
+ * Changes every end of line from CRLF, CR or LF to $this->LE.
* @access public
+ * @param string $str String to FixEOL
* @return string
*/
public function FixEOL($str) {
- $str = str_replace("\r\n", "\n", $str);
- $str = str_replace("\r", "\n", $str);
- $str = str_replace("\n", $this->LE, $str);
- return $str;
+ // condense down to \n
+ $nstr = str_replace(array("\r\n", "\r"), "\n", $str);
+ // Now convert LE as needed
+ if ($this->LE !== "\n") {
+ $nstr = str_replace("\n", $this->LE, $nstr);
+ }
+ return $nstr;
}
/**
- * Adds a custom header.
+ * Adds a custom header. $name value can be overloaded to contain
+ * both header name and value (name:value)
* @access public
+ * @param string $name custom header name
+ * @param string $value header value
* @return void
*/
- public function AddCustomHeader($custom_header) {
- $this->CustomHeader[] = explode(':', $custom_header, 2);
+ public function AddCustomHeader($name, $value=null) {
+ if ($value === null) {
+ // Value passed in as name:value
+ $this->CustomHeader[] = explode(':', $name, 2);
+ } else {
+ $this->CustomHeader[] = array($name, $value);
+ }
}
/**
- * Evaluates the message and returns modifications for inline images and backgrounds
+ * Creates a message from an HTML string, making modifications for inline images and backgrounds
+ * and creates a plain-text version by converting the HTML
+ * Overwrites any existing values in $this->Body and $this->AltBody
* @access public
- * @return $message
+ * @param string $message HTML message string
+ * @param string $basedir baseline directory for path
+ * @param bool $advanced Whether to use the advanced HTML to text converter
+ * @return string $message
*/
- public function MsgHTML($message, $basedir = '') {
- preg_match_all("/(src|background)=\"(.*)\"/Ui", $message, $images);
- if(isset($images[2])) {
- foreach($images[2] as $i => $url) {
+ public function MsgHTML($message, $basedir = '', $advanced = false) {
+ preg_match_all("/(src|background)=[\"'](.*)[\"']/Ui", $message, $images);
+ if (isset($images[2])) {
+ foreach ($images[2] as $i => $url) {
// do not change urls for absolute images (thanks to corvuscorax)
if (!preg_match('#^[A-z]+://#', $url)) {
$filename = basename($url);
$directory = dirname($url);
- ($directory == '.') ? $directory='': '';
- $cid = 'cid:' . md5($filename);
- $ext = pathinfo($filename, PATHINFO_EXTENSION);
- $mimeType = self::_mime_types($ext);
- if ( strlen($basedir) > 1 && substr($basedir, -1) != '/') { $basedir .= '/'; }
- if ( strlen($directory) > 1 && substr($directory, -1) != '/') { $directory .= '/'; }
- if ( $this->AddEmbeddedImage($basedir.$directory.$filename, md5($filename), $filename, 'base64', $mimeType) ) {
- $message = preg_replace("/".$images[1][$i]."=\"".preg_quote($url, '/')."\"/Ui", $images[1][$i]."=\"".$cid."\"", $message);
+ if ($directory == '.') {
+ $directory = '';
+ }
+ $cid = md5($url).'@phpmailer.0'; //RFC2392 S 2
+ if (strlen($basedir) > 1 && substr($basedir, -1) != '/') {
+ $basedir .= '/';
+ }
+ if (strlen($directory) > 1 && substr($directory, -1) != '/') {
+ $directory .= '/';
+ }
+ if ($this->AddEmbeddedImage($basedir.$directory.$filename, $cid, $filename, 'base64', self::_mime_types(self::mb_pathinfo($filename, PATHINFO_EXTENSION)))) {
+ $message = preg_replace("/".$images[1][$i]."=[\"']".preg_quote($url, '/')."[\"']/Ui", $images[1][$i]."=\"cid:".$cid."\"", $message);
}
}
}
}
$this->IsHTML(true);
- $this->Body = $message;
- $textMsg = trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/s', '', $message)));
- if (!empty($textMsg) && empty($this->AltBody)) {
- $this->AltBody = html_entity_decode($textMsg);
- }
if (empty($this->AltBody)) {
$this->AltBody = 'To view this email message, open it in a program that understands HTML!' . "\n\n";
}
+ //Convert all message body line breaks to CRLF, makes quoted-printable encoding work much better
+ $this->Body = $this->NormalizeBreaks($message);
+ $this->AltBody = $this->NormalizeBreaks($this->html2text($message, $advanced));
+ return $this->Body;
+ }
+
+ /**
+ * Convert an HTML string into a plain text version
+ * @param string $html The HTML text to convert
+ * @param bool $advanced Should this use the more complex html2text converter or just a simple one?
+ * @return string
+ */
+ public function html2text($html, $advanced = false) {
+ if ($advanced) {
+ require_once 'extras/class.html2text.php';
+ $h = new html2text($html);
+ return $h->get_text();
+ }
+ return html_entity_decode(trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/si', '', $html))), ENT_QUOTES, $this->CharSet);
}
/**
* Gets the MIME type of the embedded or inline image
- * @param string File extension
+ * @param string $ext File extension
* @access public
* @return string MIME type of ext
* @static
*/
public static function _mime_types($ext = '') {
$mimes = array(
+ 'xl' => 'application/excel',
'hqx' => 'application/mac-binhex40',
'cpt' => 'application/mac-compactpro',
- 'doc' => 'application/msword',
'bin' => 'application/macbinary',
+ 'doc' => 'application/msword',
+ 'word' => 'application/msword',
+ 'class' => 'application/octet-stream',
+ 'dll' => 'application/octet-stream',
'dms' => 'application/octet-stream',
+ 'exe' => 'application/octet-stream',
'lha' => 'application/octet-stream',
'lzh' => 'application/octet-stream',
- 'exe' => 'application/octet-stream',
- 'class' => 'application/octet-stream',
'psd' => 'application/octet-stream',
- 'so' => 'application/octet-stream',
'sea' => 'application/octet-stream',
- 'dll' => 'application/octet-stream',
+ 'so' => 'application/octet-stream',
'oda' => 'application/oda',
'pdf' => 'application/pdf',
'ai' => 'application/postscript',
@@ -2223,9 +2585,9 @@ class PHPMailer {
'dxr' => 'application/x-director',
'dvi' => 'application/x-dvi',
'gtar' => 'application/x-gtar',
- 'php' => 'application/x-httpd-php',
- 'php4' => 'application/x-httpd-php',
'php3' => 'application/x-httpd-php',
+ 'php4' => 'application/x-httpd-php',
+ 'php' => 'application/x-httpd-php',
'phtml' => 'application/x-httpd-php',
'phps' => 'application/x-httpd-php-source',
'js' => 'application/x-javascript',
@@ -2233,69 +2595,131 @@ class PHPMailer {
'sit' => 'application/x-stuffit',
'tar' => 'application/x-tar',
'tgz' => 'application/x-tar',
- 'xhtml' => 'application/xhtml+xml',
'xht' => 'application/xhtml+xml',
+ 'xhtml' => 'application/xhtml+xml',
'zip' => 'application/zip',
'mid' => 'audio/midi',
'midi' => 'audio/midi',
- 'mpga' => 'audio/mpeg',
'mp2' => 'audio/mpeg',
'mp3' => 'audio/mpeg',
+ 'mpga' => 'audio/mpeg',
'aif' => 'audio/x-aiff',
- 'aiff' => 'audio/x-aiff',
'aifc' => 'audio/x-aiff',
+ 'aiff' => 'audio/x-aiff',
'ram' => 'audio/x-pn-realaudio',
'rm' => 'audio/x-pn-realaudio',
'rpm' => 'audio/x-pn-realaudio-plugin',
'ra' => 'audio/x-realaudio',
- 'rv' => 'video/vnd.rn-realvideo',
'wav' => 'audio/x-wav',
'bmp' => 'image/bmp',
'gif' => 'image/gif',
'jpeg' => 'image/jpeg',
- 'jpg' => 'image/jpeg',
'jpe' => 'image/jpeg',
+ 'jpg' => 'image/jpeg',
'png' => 'image/png',
'tiff' => 'image/tiff',
'tif' => 'image/tiff',
+ 'eml' => 'message/rfc822',
'css' => 'text/css',
'html' => 'text/html',
'htm' => 'text/html',
'shtml' => 'text/html',
- 'txt' => 'text/plain',
- 'text' => 'text/plain',
'log' => 'text/plain',
+ 'text' => 'text/plain',
+ 'txt' => 'text/plain',
'rtx' => 'text/richtext',
'rtf' => 'text/rtf',
'xml' => 'text/xml',
'xsl' => 'text/xml',
'mpeg' => 'video/mpeg',
- 'mpg' => 'video/mpeg',
'mpe' => 'video/mpeg',
- 'qt' => 'video/quicktime',
+ 'mpg' => 'video/mpeg',
'mov' => 'video/quicktime',
+ 'qt' => 'video/quicktime',
+ 'rv' => 'video/vnd.rn-realvideo',
'avi' => 'video/x-msvideo',
- 'movie' => 'video/x-sgi-movie',
- 'doc' => 'application/msword',
- 'word' => 'application/msword',
- 'xl' => 'application/excel',
- 'eml' => 'message/rfc822'
+ 'movie' => 'video/x-sgi-movie'
);
return (!isset($mimes[strtolower($ext)])) ? 'application/octet-stream' : $mimes[strtolower($ext)];
}
/**
- * Set (or reset) Class Objects (variables)
- *
- * Usage Example:
- * $page->set('X-Priority', '3');
- *
- * @access public
- * @param string $name Parameter Name
- * @param mixed $value Parameter Value
- * NOTE: will not work with arrays, there are no arrays to set/reset
- * @todo Should this not be using __set() magic function?
- */
+ * Try to map a file name to a MIME type, default to application/octet-stream
+ * @param string $filename A file name or full path, does not need to exist as a file
+ * @return string
+ * @static
+ */
+ public static function filenameToType($filename) {
+ //In case the path is a URL, strip any query string before getting extension
+ $qpos = strpos($filename, '?');
+ if ($qpos !== false) {
+ $filename = substr($filename, 0, $qpos);
+ }
+ $pathinfo = self::mb_pathinfo($filename);
+ return self::_mime_types($pathinfo['extension']);
+ }
+
+ /**
+ * Drop-in replacement for pathinfo(), but multibyte-safe, cross-platform-safe, old-version-safe.
+ * Works similarly to the one in PHP >= 5.2.0
+ * @link http://www.php.net/manual/en/function.pathinfo.php#107461
+ * @param string $path A filename or path, does not need to exist as a file
+ * @param integer|string $options Either a PATHINFO_* constant, or a string name to return only the specified piece, allows 'filename' to work on PHP < 5.2
+ * @return string|array
+ * @static
+ */
+ public static function mb_pathinfo($path, $options = null) {
+ $ret = array('dirname' => '', 'basename' => '', 'extension' => '', 'filename' => '');
+ $m = array();
+ preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', $path, $m);
+ if(array_key_exists(1, $m)) {
+ $ret['dirname'] = $m[1];
+ }
+ if(array_key_exists(2, $m)) {
+ $ret['basename'] = $m[2];
+ }
+ if(array_key_exists(5, $m)) {
+ $ret['extension'] = $m[5];
+ }
+ if(array_key_exists(3, $m)) {
+ $ret['filename'] = $m[3];
+ }
+ switch($options) {
+ case PATHINFO_DIRNAME:
+ case 'dirname':
+ return $ret['dirname'];
+ break;
+ case PATHINFO_BASENAME:
+ case 'basename':
+ return $ret['basename'];
+ break;
+ case PATHINFO_EXTENSION:
+ case 'extension':
+ return $ret['extension'];
+ break;
+ case PATHINFO_FILENAME:
+ case 'filename':
+ return $ret['filename'];
+ break;
+ default:
+ return $ret;
+ }
+ }
+
+ /**
+ * Set (or reset) Class Objects (variables)
+ *
+ * Usage Example:
+ * $page->set('X-Priority', '3');
+ *
+ * @access public
+ * @param string $name
+ * @param mixed $value
+ * NOTE: will not work with arrays, there are no arrays to set/reset
+ * @throws phpmailerException
+ * @return bool
+ * @todo Should this not be using __set() magic function?
+ */
public function set($name, $value = '') {
try {
if (isset($this->$name) ) {
@@ -2315,20 +2739,33 @@ class PHPMailer {
/**
* Strips newlines to prevent header injection.
* @access public
- * @param string $str String
+ * @param string $str
* @return string
*/
public function SecureHeader($str) {
- $str = str_replace("\r", '', $str);
- $str = str_replace("\n", '', $str);
- return trim($str);
+ return trim(str_replace(array("\r", "\n"), '', $str));
}
/**
+ * Normalize UNIX LF, Mac CR and Windows CRLF line breaks into a single line break format
+ * Defaults to CRLF (for message bodies) and preserves consecutive breaks
+ * @param string $text
+ * @param string $breaktype What kind of line break to use, defaults to CRLF
+ * @return string
+ * @access public
+ * @static
+ */
+ public static function NormalizeBreaks($text, $breaktype = "\r\n") {
+ return preg_replace('/(\r\n|\r|\n)/ms', $breaktype, $text);
+ }
+
+
+ /**
* Set the private key file and password to sign the message.
*
* @access public
- * @param string $key_filename Parameter File Name
+ * @param string $cert_filename
+ * @param string $key_filename
* @param string $key_pass Password for private key
*/
public function Sign($cert_filename, $key_filename, $key_pass) {
@@ -2341,11 +2778,10 @@ class PHPMailer {
* Set the private key file and password to sign the message.
*
* @access public
- * @param string $key_filename Parameter File Name
- * @param string $key_pass Password for private key
+ * @param string $txt
+ * @return string
*/
public function DKIM_QP($txt) {
- $tmp = '';
$line = '';
for ($i = 0; $i < strlen($txt); $i++) {
$ord = ord($txt[$i]);
@@ -2363,8 +2799,16 @@ class PHPMailer {
*
* @access public
* @param string $s Header
+ * @throws phpmailerException
+ * @return string
*/
public function DKIM_Sign($s) {
+ if (!defined('PKCS7_TEXT')) {
+ if ($this->exceptions) {
+ throw new phpmailerException($this->Lang("signing").' OpenSSL extension missing.');
+ }
+ return '';
+ }
$privKeyStr = file_get_contents($this->DKIM_private);
if ($this->DKIM_passphrase != '') {
$privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase);
@@ -2374,6 +2818,7 @@ class PHPMailer {
if (openssl_sign($s, $signature, $privKey)) {
return base64_encode($signature);
}
+ return '';
}
/**
@@ -2381,6 +2826,7 @@ class PHPMailer {
*
* @access public
* @param string $s Header
+ * @return string
*/
public function DKIM_HeaderC($s) {
$s = preg_replace("/\r\n\s+/", " ", $s);
@@ -2400,6 +2846,7 @@ class PHPMailer {
*
* @access public
* @param string $body Message Body
+ * @return string
*/
public function DKIM_BodyC($body) {
if ($body == '') return "\r\n";
@@ -2420,6 +2867,7 @@ class PHPMailer {
* @param string $headers_line Header lines
* @param string $subject Subject
* @param string $body Body
+ * @return string
*/
public function DKIM_Add($headers_line, $subject, $body) {
$DKIMsignatureType = 'rsa-sha1'; // Signature & hash algorithms
@@ -2428,11 +2876,22 @@ class PHPMailer {
$DKIMtime = time() ; // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone)
$subject_header = "Subject: $subject";
$headers = explode($this->LE, $headers_line);
+ $from_header = '';
+ $to_header = '';
+ $current = '';
foreach($headers as $header) {
if (strpos($header, 'From:') === 0) {
$from_header = $header;
+ $current = 'from_header';
} elseif (strpos($header, 'To:') === 0) {
$to_header = $header;
+ $current = 'to_header';
+ } else {
+ if($current && strpos($header, ' =?') === 0){
+ $current .= $header;
+ } else {
+ $current = '';
+ }
}
}
$from = str_replace('|', '=7C', $this->DKIM_QP($from_header));
@@ -2453,21 +2912,38 @@ class PHPMailer {
"\tb=";
$toSign = $this->DKIM_HeaderC($from_header . "\r\n" . $to_header . "\r\n" . $subject_header . "\r\n" . $dkimhdrs);
$signed = $this->DKIM_Sign($toSign);
- return "X-PHPMAILER-DKIM: phpmailer.worxware.com\r\n".$dkimhdrs.$signed."\r\n";
+ return $dkimhdrs.$signed."\r\n";
}
- protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body) {
- if (!empty($this->action_function) && function_exists($this->action_function)) {
- $params = array($isSent, $to, $cc, $bcc, $subject, $body);
+ /**
+ * Perform callback
+ * @param boolean $isSent
+ * @param string $to
+ * @param string $cc
+ * @param string $bcc
+ * @param string $subject
+ * @param string $body
+ * @param string $from
+ */
+ protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from = null) {
+ if (!empty($this->action_function) && is_callable($this->action_function)) {
+ $params = array($isSent, $to, $cc, $bcc, $subject, $body, $from);
call_user_func_array($this->action_function, $params);
}
}
}
+/**
+ * Exception handler for PHPMailer
+ * @package PHPMailer
+ */
class phpmailerException extends Exception {
+ /**
+ * Prettify error message output
+ * @return string
+ */
public function errorMessage() {
$errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n";
return $errorMsg;
}
}
-?>
diff --git a/library/phpmailer/class.smtp.php b/library/phpmailer/class.smtp.php
index 22d8e951d8..4b02f99915 100644
--- a/library/phpmailer/class.smtp.php
+++ b/library/phpmailer/class.smtp.php
@@ -2,15 +2,16 @@
/*~ class.smtp.php
.---------------------------------------------------------------------------.
| Software: PHPMailer - PHP email class |
-| Version: 5.2 |
-| Site: https://code.google.com/a/apache-extras.org/p/phpmailer/ |
+| Version: 5.2.6 |
+| Site: https://github.com/PHPMailer/PHPMailer/ |
| ------------------------------------------------------------------------- |
-| Admin: Jim Jagielski (project admininistrator) |
+| Admins: Marcus Bointon |
+| Admins: Jim Jagielski |
| Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
-| : Marcus Bointon (coolbru) coolbru@users.sourceforge.net |
+| : Marcus Bointon (coolbru) phpmailer@synchromedia.co.uk |
| : Jim Jagielski (jimjag) jimjag@gmail.com |
| Founder: Brent R. Matzelle (original founder) |
-| Copyright (c) 2010-2011, Jim Jagielski. All Rights Reserved. |
+| Copyright (c) 2010-2012, Jim Jagielski. All Rights Reserved. |
| Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved. |
| Copyright (c) 2001-2003, Brent R. Matzelle |
| ------------------------------------------------------------------------- |
@@ -30,17 +31,17 @@
* @author Marcus Bointon
* @copyright 2004 - 2008 Andy Prevost
* @author Jim Jagielski
- * @copyright 2010 - 2011 Jim Jagielski
+ * @copyright 2010 - 2012 Jim Jagielski
* @license http://www.gnu.org/copyleft/lesser.html Distributed under the Lesser General Public License (LGPL)
- * @version $Id$
*/
/**
- * SMTP is rfc 821 compliant and implements all the rfc 821 SMTP
- * commands except TURN which will always return a not implemented
- * error. SMTP also provides some utility methods for sending mail
- * to an SMTP server.
- * original author: Chris Ryan
+ * PHP RFC821 SMTP client
+ *
+ * Implements all the RFC 821 SMTP commands except TURN which will always return a not implemented error.
+ * SMTP also provides some utility methods for sending mail to an SMTP server.
+ * @author Chris Ryan
+ * @package PHPMailer
*/
class SMTP {
@@ -51,16 +52,23 @@ class SMTP {
public $SMTP_PORT = 25;
/**
- * SMTP reply line ending
+ * SMTP reply line ending (don't change)
* @var string
*/
public $CRLF = "\r\n";
/**
- * Sets whether debugging is turned on
- * @var bool
+ * Debug output level; 0 for no output
+ * @var int
+ */
+ public $do_debug = 0;
+
+ /**
+ * Sets the function/method to use for debugging output.
+ * Right now we only honor 'echo', 'html' or 'error_log'
+ * @var string
*/
- public $do_debug; // the level of debug to perform
+ public $Debugoutput = 'echo';
/**
* Sets VERP use on/off (default is off)
@@ -69,23 +77,64 @@ class SMTP {
public $do_verp = false;
/**
+ * Sets the SMTP timeout value for reads, in seconds
+ * @var int
+ */
+ public $Timeout = 15;
+
+ /**
+ * Sets the SMTP timelimit value for reads, in seconds
+ * @var int
+ */
+ public $Timelimit = 30;
+
+ /**
* Sets the SMTP PHPMailer Version number
* @var string
*/
- public $Version = '5.2';
+ public $Version = '5.2.6';
/////////////////////////////////////////////////
// PROPERTIES, PRIVATE AND PROTECTED
/////////////////////////////////////////////////
- private $smtp_conn; // the socket to the server
- private $error; // error if any on the last call
- private $helo_rply; // the reply the server sent to us for HELO
+ /**
+ * @var resource The socket to the server
+ */
+ protected $smtp_conn;
+ /**
+ * @var string Error message, if any, for the last call
+ */
+ protected $error;
+ /**
+ * @var string The reply the server sent to us for HELO
+ */
+ protected $helo_rply;
+
+ /**
+ * Outputs debugging info via user-defined method
+ * @param string $str
+ */
+ protected function edebug($str) {
+ switch ($this->Debugoutput) {
+ case 'error_log':
+ error_log($str);
+ break;
+ case 'html':
+ //Cleans up output a bit for a better looking display that's HTML-safe
+ echo htmlentities(preg_replace('/[\r\n]+/', '', $str), ENT_QUOTES, 'UTF-8')."<br>\n";
+ break;
+ case 'echo':
+ default:
+ //Just echoes exactly what was received
+ echo $str;
+ }
+ }
/**
* Initialize the class so that the data is in a known state.
* @access public
- * @return void
+ * @return SMTP
*/
public function __construct() {
$this->smtp_conn = 0;
@@ -100,26 +149,25 @@ class SMTP {
/////////////////////////////////////////////////
/**
- * Connect to the server specified on the port specified.
- * If the port is not specified use the default SMTP_PORT.
- * If tval is specified then a connection will try and be
- * established with the server for that number of seconds.
- * If tval is not specified the default is 30 seconds to
- * try on the connection.
+ * Connect to an SMTP server
*
* SMTP CODE SUCCESS: 220
* SMTP CODE FAILURE: 421
* @access public
+ * @param string $host SMTP server IP or host name
+ * @param int $port The port number to connect to, or use the default port if not specified
+ * @param int $timeout How long to wait for the connection to open
+ * @param array $options An array of options compatible with stream_context_create()
* @return bool
*/
- public function Connect($host, $port = 0, $tval = 30) {
- // set the error val to null so there is no confusion
+ public function Connect($host, $port = 0, $timeout = 30, $options = array()) {
+ // Clear errors to avoid confusion
$this->error = null;
- // make sure we are __not__ connected
+ // Make sure we are __not__ connected
if($this->connected()) {
- // already connected, generate error
- $this->error = array("error" => "Already connected to a server");
+ // Already connected, generate error
+ $this->error = array('error' => 'Already connected to a server');
return false;
}
@@ -127,33 +175,39 @@ class SMTP {
$port = $this->SMTP_PORT;
}
- // connect to the smtp server
- $this->smtp_conn = @fsockopen($host, // the host of the server
- $port, // the port to use
- $errno, // error number if any
- $errstr, // error message if any
- $tval); // give up after ? secs
- // verify we connected properly
+ // Connect to the SMTP server
+ $errno = 0;
+ $errstr = '';
+ $socket_context = stream_context_create($options);
+ //Need to suppress errors here as connection failures can be handled at a higher level
+ $this->smtp_conn = @stream_socket_client($host.":".$port, $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $socket_context);
+
+ // Verify we connected properly
if(empty($this->smtp_conn)) {
- $this->error = array("error" => "Failed to connect to server",
- "errno" => $errno,
- "errstr" => $errstr);
+ $this->error = array('error' => 'Failed to connect to server',
+ 'errno' => $errno,
+ 'errstr' => $errstr);
if($this->do_debug >= 1) {
- echo "SMTP -> ERROR: " . $this->error["error"] . ": $errstr ($errno)" . $this->CRLF . '<br />';
+ $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ": $errstr ($errno)");
}
return false;
}
// SMTP server can take longer to respond, give longer timeout for first read
// Windows does not have support for this timeout function
- if(substr(PHP_OS, 0, 3) != "WIN")
- socket_set_timeout($this->smtp_conn, $tval, 0);
+ if(substr(PHP_OS, 0, 3) != 'WIN') {
+ $max = ini_get('max_execution_time');
+ if ($max != 0 && $timeout > $max) { // Don't bother if unlimited
+ @set_time_limit($timeout);
+ }
+ stream_set_timeout($this->smtp_conn, $timeout, 0);
+ }
// get any announcement
$announce = $this->get_lines();
if($this->do_debug >= 2) {
- echo "SMTP -> FROM SERVER:" . $announce . $this->CRLF . '<br />';
+ $this->edebug('SMTP -> FROM SERVER:' . $announce);
}
return true;
@@ -172,26 +226,26 @@ class SMTP {
$this->error = null; # to avoid confusion
if(!$this->connected()) {
- $this->error = array("error" => "Called StartTLS() without being connected");
+ $this->error = array('error' => 'Called StartTLS() without being connected');
return false;
}
- fputs($this->smtp_conn,"STARTTLS" . $this->CRLF);
+ $this->client_send('STARTTLS' . $this->CRLF);
$rply = $this->get_lines();
- $code = substr($rply,0,3);
+ $code = substr($rply, 0, 3);
if($this->do_debug >= 2) {
- echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
+ $this->edebug('SMTP -> FROM SERVER:' . $rply);
}
if($code != 220) {
$this->error =
- array("error" => "STARTTLS not accepted from server",
- "smtp_code" => $code,
- "smtp_msg" => substr($rply,4));
+ array('error' => 'STARTTLS not accepted from server',
+ 'smtp_code' => $code,
+ 'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
- echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
+ $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
@@ -208,61 +262,237 @@ class SMTP {
* Performs SMTP authentication. Must be run after running the
* Hello() method. Returns true if successfully authenticated.
* @access public
+ * @param string $username
+ * @param string $password
+ * @param string $authtype
+ * @param string $realm
+ * @param string $workstation
* @return bool
*/
- public function Authenticate($username, $password) {
- // Start authentication
- fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF);
+ public function Authenticate($username, $password, $authtype='LOGIN', $realm='', $workstation='') {
+ if (empty($authtype)) {
+ $authtype = 'LOGIN';
+ }
- $rply = $this->get_lines();
- $code = substr($rply,0,3);
+ switch ($authtype) {
+ case 'PLAIN':
+ // Start authentication
+ $this->client_send('AUTH PLAIN' . $this->CRLF);
- if($code != 334) {
- $this->error =
- array("error" => "AUTH not accepted from server",
- "smtp_code" => $code,
- "smtp_msg" => substr($rply,4));
- if($this->do_debug >= 1) {
- echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
- }
- return false;
- }
+ $rply = $this->get_lines();
+ $code = substr($rply, 0, 3);
- // Send encoded username
- fputs($this->smtp_conn, base64_encode($username) . $this->CRLF);
+ if($code != 334) {
+ $this->error =
+ array('error' => 'AUTH not accepted from server',
+ 'smtp_code' => $code,
+ 'smtp_msg' => substr($rply, 4));
+ if($this->do_debug >= 1) {
+ $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
+ }
+ return false;
+ }
+ // Send encoded username and password
+ $this->client_send(base64_encode("\0".$username."\0".$password) . $this->CRLF);
- $rply = $this->get_lines();
- $code = substr($rply,0,3);
+ $rply = $this->get_lines();
+ $code = substr($rply, 0, 3);
- if($code != 334) {
- $this->error =
- array("error" => "Username not accepted from server",
- "smtp_code" => $code,
- "smtp_msg" => substr($rply,4));
- if($this->do_debug >= 1) {
- echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
- }
- return false;
+ if($code != 235) {
+ $this->error =
+ array('error' => 'Authentication not accepted from server',
+ 'smtp_code' => $code,
+ 'smtp_msg' => substr($rply, 4));
+ if($this->do_debug >= 1) {
+ $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
+ }
+ return false;
+ }
+ break;
+ case 'LOGIN':
+ // Start authentication
+ $this->client_send('AUTH LOGIN' . $this->CRLF);
+
+ $rply = $this->get_lines();
+ $code = substr($rply, 0, 3);
+
+ if($code != 334) {
+ $this->error =
+ array('error' => 'AUTH not accepted from server',
+ 'smtp_code' => $code,
+ 'smtp_msg' => substr($rply, 4));
+ if($this->do_debug >= 1) {
+ $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
+ }
+ return false;
+ }
+
+ // Send encoded username
+ $this->client_send(base64_encode($username) . $this->CRLF);
+
+ $rply = $this->get_lines();
+ $code = substr($rply, 0, 3);
+
+ if($code != 334) {
+ $this->error =
+ array('error' => 'Username not accepted from server',
+ 'smtp_code' => $code,
+ 'smtp_msg' => substr($rply, 4));
+ if($this->do_debug >= 1) {
+ $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
+ }
+ return false;
+ }
+
+ // Send encoded password
+ $this->client_send(base64_encode($password) . $this->CRLF);
+
+ $rply = $this->get_lines();
+ $code = substr($rply, 0, 3);
+
+ if($code != 235) {
+ $this->error =
+ array('error' => 'Password not accepted from server',
+ 'smtp_code' => $code,
+ 'smtp_msg' => substr($rply, 4));
+ if($this->do_debug >= 1) {
+ $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
+ }
+ return false;
+ }
+ break;
+ case 'NTLM':
+ /*
+ * ntlm_sasl_client.php
+ ** Bundled with Permission
+ **
+ ** How to telnet in windows: http://technet.microsoft.com/en-us/library/aa995718%28EXCHG.65%29.aspx
+ ** PROTOCOL Documentation http://curl.haxx.se/rfc/ntlm.html#ntlmSmtpAuthentication
+ */
+ require_once 'extras/ntlm_sasl_client.php';
+ $temp = new stdClass();
+ $ntlm_client = new ntlm_sasl_client_class;
+ if(! $ntlm_client->Initialize($temp)){//let's test if every function its available
+ $this->error = array('error' => $temp->error);
+ if($this->do_debug >= 1) {
+ $this->edebug('You need to enable some modules in your php.ini file: ' . $this->error['error']);
+ }
+ return false;
+ }
+ $msg1 = $ntlm_client->TypeMsg1($realm, $workstation);//msg1
+
+ $this->client_send('AUTH NTLM ' . base64_encode($msg1) . $this->CRLF);
+
+ $rply = $this->get_lines();
+ $code = substr($rply, 0, 3);
+
+ if($code != 334) {
+ $this->error =
+ array('error' => 'AUTH not accepted from server',
+ 'smtp_code' => $code,
+ 'smtp_msg' => substr($rply, 4));
+ if($this->do_debug >= 1) {
+ $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
+ }
+ return false;
+ }
+
+ $challenge = substr($rply, 3);//though 0 based, there is a white space after the 3 digit number....//msg2
+ $challenge = base64_decode($challenge);
+ $ntlm_res = $ntlm_client->NTLMResponse(substr($challenge, 24, 8), $password);
+ $msg3 = $ntlm_client->TypeMsg3($ntlm_res, $username, $realm, $workstation);//msg3
+ // Send encoded username
+ $this->client_send(base64_encode($msg3) . $this->CRLF);
+
+ $rply = $this->get_lines();
+ $code = substr($rply, 0, 3);
+
+ if($code != 235) {
+ $this->error =
+ array('error' => 'Could not authenticate',
+ 'smtp_code' => $code,
+ 'smtp_msg' => substr($rply, 4));
+ if($this->do_debug >= 1) {
+ $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
+ }
+ return false;
+ }
+ break;
+ case 'CRAM-MD5':
+ // Start authentication
+ $this->client_send('AUTH CRAM-MD5' . $this->CRLF);
+
+ $rply = $this->get_lines();
+ $code = substr($rply, 0, 3);
+
+ if($code != 334) {
+ $this->error =
+ array('error' => 'AUTH not accepted from server',
+ 'smtp_code' => $code,
+ 'smtp_msg' => substr($rply, 4));
+ if($this->do_debug >= 1) {
+ $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
+ }
+ return false;
+ }
+
+ // Get the challenge
+ $challenge = base64_decode(substr($rply, 4));
+
+ // Build the response
+ $response = $username . ' ' . $this->hmac($challenge, $password);
+
+ // Send encoded credentials
+ $this->client_send(base64_encode($response) . $this->CRLF);
+
+ $rply = $this->get_lines();
+ $code = substr($rply, 0, 3);
+
+ if($code != 235) {
+ $this->error =
+ array('error' => 'Credentials not accepted from server',
+ 'smtp_code' => $code,
+ 'smtp_msg' => substr($rply, 4));
+ if($this->do_debug >= 1) {
+ $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
+ }
+ return false;
+ }
+ break;
}
+ return true;
+ }
- // Send encoded password
- fputs($this->smtp_conn, base64_encode($password) . $this->CRLF);
+ /**
+ * Works like hash_hmac('md5', $data, $key) in case that function is not available
+ * @access protected
+ * @param string $data
+ * @param string $key
+ * @return string
+ */
+ protected function hmac($data, $key) {
+ if (function_exists('hash_hmac')) {
+ return hash_hmac('md5', $data, $key);
+ }
- $rply = $this->get_lines();
- $code = substr($rply,0,3);
+ // The following borrowed from http://php.net/manual/en/function.mhash.php#27225
- if($code != 235) {
- $this->error =
- array("error" => "Password not accepted from server",
- "smtp_code" => $code,
- "smtp_msg" => substr($rply,4));
- if($this->do_debug >= 1) {
- echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
+ // RFC 2104 HMAC implementation for php.
+ // Creates an md5 HMAC.
+ // Eliminates the need to install mhash to compute a HMAC
+ // Hacked by Lance Rushing
+
+ $b = 64; // byte length for md5
+ if (strlen($key) > $b) {
+ $key = pack('H*', md5($key));
}
- return false;
- }
+ $key = str_pad($key, $b, chr(0x00));
+ $ipad = str_pad('', $b, chr(0x36));
+ $opad = str_pad('', $b, chr(0x5c));
+ $k_ipad = $key ^ $ipad ;
+ $k_opad = $key ^ $opad;
- return true;
+ return md5($k_opad . pack('H*', md5($k_ipad . $data)));
}
/**
@@ -272,11 +502,11 @@ class SMTP {
*/
public function Connected() {
if(!empty($this->smtp_conn)) {
- $sock_status = socket_get_status($this->smtp_conn);
- if($sock_status["eof"]) {
+ $sock_status = stream_get_meta_data($this->smtp_conn);
+ if($sock_status['eof']) {
// the socket is valid but we are not connected
if($this->do_debug >= 1) {
- echo "SMTP -> NOTICE:" . $this->CRLF . "EOF caught while checking if connected";
+ $this->edebug('SMTP -> NOTICE: EOF caught while checking if connected');
}
$this->Close();
return false;
@@ -312,7 +542,7 @@ class SMTP {
* finializing the mail transaction. $msg_data is the message
* that is to be send with the headers. Each header needs to be
* on a single line followed by a <CRLF> with the message headers
- * and the message body being seperated by and additional <CRLF>.
+ * and the message body being separated by and additional <CRLF>.
*
* Implements rfc 821: DATA <CRLF>
*
@@ -320,10 +550,11 @@ class SMTP {
* [data]
* <CRLF>.<CRLF>
* SMTP CODE SUCCESS: 250
- * SMTP CODE FAILURE: 552,554,451,452
- * SMTP CODE FAILURE: 451,554
- * SMTP CODE ERROR : 500,501,503,421
+ * SMTP CODE FAILURE: 552, 554, 451, 452
+ * SMTP CODE FAILURE: 451, 554
+ * SMTP CODE ERROR : 500, 501, 503, 421
* @access public
+ * @param string $msg_data
* @return bool
*/
public function Data($msg_data) {
@@ -331,26 +562,26 @@ class SMTP {
if(!$this->connected()) {
$this->error = array(
- "error" => "Called Data() without being connected");
+ 'error' => 'Called Data() without being connected');
return false;
}
- fputs($this->smtp_conn,"DATA" . $this->CRLF);
+ $this->client_send('DATA' . $this->CRLF);
$rply = $this->get_lines();
- $code = substr($rply,0,3);
+ $code = substr($rply, 0, 3);
if($this->do_debug >= 2) {
- echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
+ $this->edebug('SMTP -> FROM SERVER:' . $rply);
}
if($code != 354) {
$this->error =
- array("error" => "DATA command not accepted from server",
- "smtp_code" => $code,
- "smtp_msg" => substr($rply,4));
+ array('error' => 'DATA command not accepted from server',
+ 'smtp_code' => $code,
+ 'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
- echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
+ $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
@@ -367,9 +598,9 @@ class SMTP {
*/
// normalize the line breaks so we know the explode works
- $msg_data = str_replace("\r\n","\n",$msg_data);
- $msg_data = str_replace("\r","\n",$msg_data);
- $lines = explode("\n",$msg_data);
+ $msg_data = str_replace("\r\n", "\n", $msg_data);
+ $msg_data = str_replace("\r", "\n", $msg_data);
+ $lines = explode("\n", $msg_data);
/* we need to find a good way to determine is headers are
* in the msg_data or if it is a straight msg body
@@ -380,31 +611,31 @@ class SMTP {
* headers.
*/
- $field = substr($lines[0],0,strpos($lines[0],":"));
+ $field = substr($lines[0], 0, strpos($lines[0], ':'));
$in_headers = false;
- if(!empty($field) && !strstr($field," ")) {
+ if(!empty($field) && !strstr($field, ' ')) {
$in_headers = true;
}
$max_line_length = 998; // used below; set here for ease in change
- while(list(,$line) = @each($lines)) {
+ while(list(, $line) = @each($lines)) {
$lines_out = null;
- if($line == "" && $in_headers) {
+ if($line == '' && $in_headers) {
$in_headers = false;
}
// ok we need to break this line up into several smaller lines
while(strlen($line) > $max_line_length) {
- $pos = strrpos(substr($line,0,$max_line_length)," ");
+ $pos = strrpos(substr($line, 0, $max_line_length), ' ');
// Patch to fix DOS attack
if(!$pos) {
$pos = $max_line_length - 1;
- $lines_out[] = substr($line,0,$pos);
- $line = substr($line,$pos);
+ $lines_out[] = substr($line, 0, $pos);
+ $line = substr($line, $pos);
} else {
- $lines_out[] = substr($line,0,$pos);
- $line = substr($line,$pos + 1);
+ $lines_out[] = substr($line, 0, $pos);
+ $line = substr($line, $pos + 1);
}
/* if processing headers add a LWSP-char to the front of new line
@@ -417,34 +648,34 @@ class SMTP {
$lines_out[] = $line;
// send the lines to the server
- while(list(,$line_out) = @each($lines_out)) {
+ while(list(, $line_out) = @each($lines_out)) {
if(strlen($line_out) > 0)
{
- if(substr($line_out, 0, 1) == ".") {
- $line_out = "." . $line_out;
+ if(substr($line_out, 0, 1) == '.') {
+ $line_out = '.' . $line_out;
}
}
- fputs($this->smtp_conn,$line_out . $this->CRLF);
+ $this->client_send($line_out . $this->CRLF);
}
}
// message data has been sent
- fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF);
+ $this->client_send($this->CRLF . '.' . $this->CRLF);
$rply = $this->get_lines();
- $code = substr($rply,0,3);
+ $code = substr($rply, 0, 3);
if($this->do_debug >= 2) {
- echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
+ $this->edebug('SMTP -> FROM SERVER:' . $rply);
}
if($code != 250) {
$this->error =
- array("error" => "DATA not accepted from server",
- "smtp_code" => $code,
- "smtp_msg" => substr($rply,4));
+ array('error' => 'DATA not accepted from server',
+ 'smtp_code' => $code,
+ 'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
- echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
+ $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
@@ -461,6 +692,7 @@ class SMTP {
* SMTP CODE SUCCESS: 250
* SMTP CODE ERROR : 500, 501, 504, 421
* @access public
+ * @param string $host
* @return bool
*/
public function Hello($host = '') {
@@ -468,19 +700,19 @@ class SMTP {
if(!$this->connected()) {
$this->error = array(
- "error" => "Called Hello() without being connected");
+ 'error' => 'Called Hello() without being connected');
return false;
}
// if hostname for HELO was not specified send default
if(empty($host)) {
// determine appropriate default to send to server
- $host = "localhost";
+ $host = 'localhost';
}
// Send extended hello first (RFC 2821)
- if(!$this->SendHello("EHLO", $host)) {
- if(!$this->SendHello("HELO", $host)) {
+ if(!$this->SendHello('EHLO', $host)) {
+ if(!$this->SendHello('HELO', $host)) {
return false;
}
}
@@ -490,26 +722,28 @@ class SMTP {
/**
* Sends a HELO/EHLO command.
- * @access private
+ * @access protected
+ * @param string $hello
+ * @param string $host
* @return bool
*/
- private function SendHello($hello, $host) {
- fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF);
+ protected function SendHello($hello, $host) {
+ $this->client_send($hello . ' ' . $host . $this->CRLF);
$rply = $this->get_lines();
- $code = substr($rply,0,3);
+ $code = substr($rply, 0, 3);
if($this->do_debug >= 2) {
- echo "SMTP -> FROM SERVER: " . $rply . $this->CRLF . '<br />';
+ $this->edebug('SMTP -> FROM SERVER: ' . $rply);
}
if($code != 250) {
$this->error =
- array("error" => $hello . " not accepted from server",
- "smtp_code" => $code,
- "smtp_msg" => substr($rply,4));
+ array('error' => $hello . ' not accepted from server',
+ 'smtp_code' => $code,
+ 'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
- echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
+ $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
@@ -528,9 +762,10 @@ class SMTP {
* Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
*
* SMTP CODE SUCCESS: 250
- * SMTP CODE SUCCESS: 552,451,452
- * SMTP CODE SUCCESS: 500,501,421
+ * SMTP CODE SUCCESS: 552, 451, 452
+ * SMTP CODE SUCCESS: 500, 501, 421
* @access public
+ * @param string $from
* @return bool
*/
public function Mail($from) {
@@ -538,27 +773,27 @@ class SMTP {
if(!$this->connected()) {
$this->error = array(
- "error" => "Called Mail() without being connected");
+ 'error' => 'Called Mail() without being connected');
return false;
}
- $useVerp = ($this->do_verp ? "XVERP" : "");
- fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF);
+ $useVerp = ($this->do_verp ? ' XVERP' : '');
+ $this->client_send('MAIL FROM:<' . $from . '>' . $useVerp . $this->CRLF);
$rply = $this->get_lines();
- $code = substr($rply,0,3);
+ $code = substr($rply, 0, 3);
if($this->do_debug >= 2) {
- echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
+ $this->edebug('SMTP -> FROM SERVER:' . $rply);
}
if($code != 250) {
$this->error =
- array("error" => "MAIL not accepted from server",
- "smtp_code" => $code,
- "smtp_msg" => substr($rply,4));
+ array('error' => 'MAIL not accepted from server',
+ 'smtp_code' => $code,
+ 'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
- echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
+ $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
@@ -574,6 +809,7 @@ class SMTP {
* SMTP CODE SUCCESS: 221
* SMTP CODE ERROR : 500
* @access public
+ * @param bool $close_on_error
* @return bool
*/
public function Quit($close_on_error = true) {
@@ -581,32 +817,32 @@ class SMTP {
if(!$this->connected()) {
$this->error = array(
- "error" => "Called Quit() without being connected");
+ 'error' => 'Called Quit() without being connected');
return false;
}
// send the quit command to the server
- fputs($this->smtp_conn,"quit" . $this->CRLF);
+ $this->client_send('quit' . $this->CRLF);
// get any good-bye messages
$byemsg = $this->get_lines();
if($this->do_debug >= 2) {
- echo "SMTP -> FROM SERVER:" . $byemsg . $this->CRLF . '<br />';
+ $this->edebug('SMTP -> FROM SERVER:' . $byemsg);
}
$rval = true;
$e = null;
- $code = substr($byemsg,0,3);
+ $code = substr($byemsg, 0, 3);
if($code != 221) {
// use e as a tmp var cause Close will overwrite $this->error
- $e = array("error" => "SMTP server rejected quit command",
- "smtp_code" => $code,
- "smtp_rply" => substr($byemsg,4));
+ $e = array('error' => 'SMTP server rejected quit command',
+ 'smtp_code' => $code,
+ 'smtp_rply' => substr($byemsg, 4));
$rval = false;
if($this->do_debug >= 1) {
- echo "SMTP -> ERROR: " . $e["error"] . ": " . $byemsg . $this->CRLF . '<br />';
+ $this->edebug('SMTP -> ERROR: ' . $e['error'] . ': ' . $byemsg);
}
}
@@ -623,10 +859,11 @@ class SMTP {
*
* Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
*
- * SMTP CODE SUCCESS: 250,251
- * SMTP CODE FAILURE: 550,551,552,553,450,451,452
- * SMTP CODE ERROR : 500,501,503,421
+ * SMTP CODE SUCCESS: 250, 251
+ * SMTP CODE FAILURE: 550, 551, 552, 553, 450, 451, 452
+ * SMTP CODE ERROR : 500, 501, 503, 421
* @access public
+ * @param string $to
* @return bool
*/
public function Recipient($to) {
@@ -634,26 +871,26 @@ class SMTP {
if(!$this->connected()) {
$this->error = array(
- "error" => "Called Recipient() without being connected");
+ 'error' => 'Called Recipient() without being connected');
return false;
}
- fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF);
+ $this->client_send('RCPT TO:<' . $to . '>' . $this->CRLF);
$rply = $this->get_lines();
- $code = substr($rply,0,3);
+ $code = substr($rply, 0, 3);
if($this->do_debug >= 2) {
- echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
+ $this->edebug('SMTP -> FROM SERVER:' . $rply);
}
if($code != 250 && $code != 251) {
$this->error =
- array("error" => "RCPT not accepted from server",
- "smtp_code" => $code,
- "smtp_msg" => substr($rply,4));
+ array('error' => 'RCPT not accepted from server',
+ 'smtp_code' => $code,
+ 'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
- echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
+ $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
@@ -668,7 +905,7 @@ class SMTP {
* Implements rfc 821: RSET <CRLF>
*
* SMTP CODE SUCCESS: 250
- * SMTP CODE ERROR : 500,501,504,421
+ * SMTP CODE ERROR : 500, 501, 504, 421
* @access public
* @return bool
*/
@@ -676,27 +913,26 @@ class SMTP {
$this->error = null; // so no confusion is caused
if(!$this->connected()) {
- $this->error = array(
- "error" => "Called Reset() without being connected");
+ $this->error = array('error' => 'Called Reset() without being connected');
return false;
}
- fputs($this->smtp_conn,"RSET" . $this->CRLF);
+ $this->client_send('RSET' . $this->CRLF);
$rply = $this->get_lines();
- $code = substr($rply,0,3);
+ $code = substr($rply, 0, 3);
if($this->do_debug >= 2) {
- echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
+ $this->edebug('SMTP -> FROM SERVER:' . $rply);
}
if($code != 250) {
$this->error =
- array("error" => "RSET failed",
- "smtp_code" => $code,
- "smtp_msg" => substr($rply,4));
+ array('error' => 'RSET failed',
+ 'smtp_code' => $code,
+ 'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
- echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
+ $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
@@ -715,9 +951,10 @@ class SMTP {
* Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>
*
* SMTP CODE SUCCESS: 250
- * SMTP CODE SUCCESS: 552,451,452
- * SMTP CODE SUCCESS: 500,501,502,421
+ * SMTP CODE SUCCESS: 552, 451, 452
+ * SMTP CODE SUCCESS: 500, 501, 502, 421
* @access public
+ * @param string $from
* @return bool
*/
public function SendAndMail($from) {
@@ -725,26 +962,26 @@ class SMTP {
if(!$this->connected()) {
$this->error = array(
- "error" => "Called SendAndMail() without being connected");
+ 'error' => 'Called SendAndMail() without being connected');
return false;
}
- fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF);
+ $this->client_send('SAML FROM:' . $from . $this->CRLF);
$rply = $this->get_lines();
- $code = substr($rply,0,3);
+ $code = substr($rply, 0, 3);
if($this->do_debug >= 2) {
- echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
+ $this->edebug('SMTP -> FROM SERVER:' . $rply);
}
if($code != 250) {
$this->error =
- array("error" => "SAML not accepted from server",
- "smtp_code" => $code,
- "smtp_msg" => substr($rply,4));
+ array('error' => 'SAML not accepted from server',
+ 'smtp_code' => $code,
+ 'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
- echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
+ $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
@@ -765,15 +1002,28 @@ class SMTP {
* @return bool
*/
public function Turn() {
- $this->error = array("error" => "This method, TURN, of the SMTP ".
- "is not implemented");
+ $this->error = array('error' => 'This method, TURN, of the SMTP '.
+ 'is not implemented');
if($this->do_debug >= 1) {
- echo "SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF . '<br />';
+ $this->edebug('SMTP -> NOTICE: ' . $this->error['error']);
}
return false;
}
/**
+ * Sends data to the server
+ * @param string $data
+ * @access public
+ * @return Integer number of bytes sent to the server or FALSE on error
+ */
+ public function client_send($data) {
+ if ($this->do_debug >= 1) {
+ $this->edebug("CLIENT -> SMTP: $data");
+ }
+ return fwrite($this->smtp_conn, $data);
+ }
+
+ /**
* Get the current error
* @access public
* @return array
@@ -792,26 +1042,51 @@ class SMTP {
* With SMTP we can tell if we have more lines to read if the
* 4th character is '-' symbol. If it is a space then we don't
* need to read anything else.
- * @access private
+ * @access protected
* @return string
*/
- private function get_lines() {
- $data = "";
- while($str = @fgets($this->smtp_conn,515)) {
+ protected function get_lines() {
+ $data = '';
+ $endtime = 0;
+ /* If for some reason the fp is bad, don't inf loop */
+ if (!is_resource($this->smtp_conn)) {
+ return $data;
+ }
+ stream_set_timeout($this->smtp_conn, $this->Timeout);
+ if ($this->Timelimit > 0) {
+ $endtime = time() + $this->Timelimit;
+ }
+ while(is_resource($this->smtp_conn) && !feof($this->smtp_conn)) {
+ $str = @fgets($this->smtp_conn, 515);
if($this->do_debug >= 4) {
- echo "SMTP -> get_lines(): \$data was \"$data\"" . $this->CRLF . '<br />';
- echo "SMTP -> get_lines(): \$str is \"$str\"" . $this->CRLF . '<br />';
+ $this->edebug("SMTP -> get_lines(): \$data was \"$data\"");
+ $this->edebug("SMTP -> get_lines(): \$str is \"$str\"");
}
$data .= $str;
if($this->do_debug >= 4) {
- echo "SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF . '<br />';
+ $this->edebug("SMTP -> get_lines(): \$data is \"$data\"");
}
// if 4th character is a space, we are done reading, break the loop
- if(substr($str,3,1) == " ") { break; }
+ if(substr($str, 3, 1) == ' ') { break; }
+ // Timed-out? Log and break
+ $info = stream_get_meta_data($this->smtp_conn);
+ if ($info['timed_out']) {
+ if($this->do_debug >= 4) {
+ $this->edebug('SMTP -> get_lines(): timed-out (' . $this->Timeout . ' seconds)');
+ }
+ break;
+ }
+ // Now check if reads took too long
+ if ($endtime) {
+ if (time() > $endtime) {
+ if($this->do_debug >= 4) {
+ $this->edebug('SMTP -> get_lines(): timelimit reached (' . $this->Timelimit . ' seconds)');
+ }
+ break;
+ }
+ }
}
return $data;
}
}
-
-?>
diff --git a/library/phpmailer/language/phpmailer.lang-ar.php b/library/phpmailer/language/phpmailer.lang-ar.php
index b7c5057d0c..67364e967a 100644
--- a/library/phpmailer/language/phpmailer.lang-ar.php
+++ b/library/phpmailer/language/phpmailer.lang-ar.php
@@ -15,7 +15,7 @@ $PHPMAILER_LANG['file_access'] = 'لم نستطع الوصول للمل
$PHPMAILER_LANG['file_open'] = 'File Error: لم نستطع فتح الملف: ';
$PHPMAILER_LANG['from_failed'] = 'البريد التالي لم نستطع ارسال البريد له : ';
$PHPMAILER_LANG['instantiate'] = 'لم نستطع توفير خدمة البريد.';
-//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: ';
+//$PHPMAILER_LANG['invalid_address'] = 'Not sending, email address is invalid: ';
$PHPMAILER_LANG['mailer_not_supported'] = ' mailer غير مدعوم.';
//$PHPMAILER_LANG['provide_address'] = 'You must provide at least one recipient email address.';
$PHPMAILER_LANG['recipients_failed'] = 'SMTP Error: الأخطاء التالية ' .
@@ -24,4 +24,3 @@ $PHPMAILER_LANG['signing'] = 'خطأ في التوقيع: ';
//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.';
//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: ';
//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: ';
-?> \ No newline at end of file
diff --git a/library/phpmailer/language/phpmailer.lang-br.php b/library/phpmailer/language/phpmailer.lang-br.php
index 6afe60b18c..87ecbdfa5e 100644
--- a/library/phpmailer/language/phpmailer.lang-br.php
+++ b/library/phpmailer/language/phpmailer.lang-br.php
@@ -3,24 +3,24 @@
* PHPMailer language file: refer to English translation for definitive list
* Portuguese Version
* By Paulo Henrique Garcia - paulo@controllerweb.com.br
+* Edited by Lucas Guimarães - lucas@lucasguimaraes.com
*/
$PHPMAILER_LANG['authenticate'] = 'Erro de SMTP: Não foi possível autenticar.';
$PHPMAILER_LANG['connect_host'] = 'Erro de SMTP: Não foi possível conectar com o servidor SMTP.';
-$PHPMAILER_LANG['data_not_accepted'] = 'Erro de SMTP: Dados não aceitos.';
-//$PHPMAILER_LANG['empty_message'] = 'Message body empty';
+$PHPMAILER_LANG['data_not_accepted'] = 'Erro de SMTP: Dados rejeitados.';
+$PHPMAILER_LANG['empty_message'] = 'Corpo da mensagem vazio';
$PHPMAILER_LANG['encoding'] = 'Codificação desconhecida: ';
$PHPMAILER_LANG['execute'] = 'Não foi possível executar: ';
$PHPMAILER_LANG['file_access'] = 'Não foi possível acessar o arquivo: ';
$PHPMAILER_LANG['file_open'] = 'Erro de Arquivo: Não foi possível abrir o arquivo: ';
-$PHPMAILER_LANG['from_failed'] = 'Os endereços de rementente a seguir falharam: ';
-$PHPMAILER_LANG['instantiate'] = 'Não foi possível instanciar a função mail.';
-//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: ';
-$PHPMAILER_LANG['mailer_not_supported'] = ' mailer não suportado.';
-$PHPMAILER_LANG['provide_address'] = 'Você deve fornecer pelo menos um endereço de destinatário de email.';
+$PHPMAILER_LANG['from_failed'] = 'Os endereços dos remententes a seguir falharam: ';
+$PHPMAILER_LANG['instantiate'] = 'Não foi possível iniciar uma instância da função mail.';
+$PHPMAILER_LANG['invalid_address'] = 'Não enviando, endereço de e-mail inválido: ';
+$PHPMAILER_LANG['mailer_not_supported'] = ' mailer não é suportado.';
+$PHPMAILER_LANG['provide_address'] = 'Você deve fornecer pelo menos um endereço de destinatário de e-mail.';
$PHPMAILER_LANG['recipients_failed'] = 'Erro de SMTP: Os endereços de destinatário a seguir falharam: ';
-//$PHPMAILER_LANG['signing'] = 'Signing Error: ';
-//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.';
-//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: ';
-//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: ';
-?> \ No newline at end of file
+$PHPMAILER_LANG['signing'] = 'Erro ao assinar: ';
+$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() falhou.';
+$PHPMAILER_LANG['smtp_error'] = 'Erro de servidor SMTP: ';
+$PHPMAILER_LANG['variable_set'] = 'Não foi possível definir ou resetar a variável: ';
diff --git a/library/phpmailer/language/phpmailer.lang-ca.php b/library/phpmailer/language/phpmailer.lang-ca.php
index 4a160a21eb..dc563e77f6 100644
--- a/library/phpmailer/language/phpmailer.lang-ca.php
+++ b/library/phpmailer/language/phpmailer.lang-ca.php
@@ -15,7 +15,7 @@ $PHPMAILER_LANG['file_access'] = 'No es pot accedir a l\'arxiu: ';
$PHPMAILER_LANG['file_open'] = 'Error d\'Arxiu: No es pot obrir l\'arxiu: ';
$PHPMAILER_LANG['from_failed'] = 'La(s) següent(s) adreces de remitent han fallat: ';
$PHPMAILER_LANG['instantiate'] = 'No s\'ha pogut crear una instància de la funció Mail.';
-//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: ';
+//$PHPMAILER_LANG['invalid_address'] = 'Not sending, email address is invalid: ';
$PHPMAILER_LANG['mailer_not_supported'] = ' mailer no està suportat';
$PHPMAILER_LANG['provide_address'] = 'S\'ha de proveir almenys una adreça d\'email com a destinatari.';
$PHPMAILER_LANG['recipients_failed'] = 'Error SMTP: Els següents destinataris han fallat: ';
@@ -23,4 +23,3 @@ $PHPMAILER_LANG['recipients_failed'] = 'Error SMTP: Els següents destinatari
//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.';
//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: ';
//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: ';
-?> \ No newline at end of file
diff --git a/library/phpmailer/language/phpmailer.lang-ch.php b/library/phpmailer/language/phpmailer.lang-ch.php
index 31ebd861cb..d28eba611b 100644
--- a/library/phpmailer/language/phpmailer.lang-ch.php
+++ b/library/phpmailer/language/phpmailer.lang-ch.php
@@ -15,7 +15,7 @@ $PHPMAILER_LANG['file_access'] = '不能访问文件:';
$PHPMAILER_LANG['file_open'] = '文件错误:不能打开文件:';
$PHPMAILER_LANG['from_failed'] = '下面的发送地址邮件发送失败了: ';
$PHPMAILER_LANG['instantiate'] = '不能实现mail方法。';
-//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: ';
+//$PHPMAILER_LANG['invalid_address'] = 'Not sending, email address is invalid: ';
$PHPMAILER_LANG['mailer_not_supported'] = ' 您所选择的发送邮件的方法并不支持。';
$PHPMAILER_LANG['provide_address'] = '您必须提供至少一个 收信人的email地址。';
$PHPMAILER_LANG['recipients_failed'] = 'SMTP 错误: 下面的 收件人失败了: ';
@@ -23,4 +23,3 @@ $PHPMAILER_LANG['recipients_failed'] = 'SMTP 错误: 下面的 收件人失败
//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.';
//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: ';
//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: ';
-?> \ No newline at end of file
diff --git a/library/phpmailer/language/phpmailer.lang-cz.php b/library/phpmailer/language/phpmailer.lang-cz.php
index 1c8b206392..b1f0a51c28 100644
--- a/library/phpmailer/language/phpmailer.lang-cz.php
+++ b/library/phpmailer/language/phpmailer.lang-cz.php
@@ -14,7 +14,7 @@ $PHPMAILER_LANG['file_access'] = 'Soubor nenalezen: ';
$PHPMAILER_LANG['file_open'] = 'File Error: Nelze otevøít soubor pro ètení: ';
$PHPMAILER_LANG['from_failed'] = 'Následující adresa From je nesprávná: ';
$PHPMAILER_LANG['instantiate'] = 'Nelze vytvoøit instanci emailové funkce.';
-//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: ';
+//$PHPMAILER_LANG['invalid_address'] = 'Not sending, email address is invalid: ';
$PHPMAILER_LANG['mailer_not_supported'] = ' mailový klient není podporován.';
$PHPMAILER_LANG['provide_address'] = 'Musíte zadat alespoò jednu emailovou adresu pøíjemce.';
$PHPMAILER_LANG['recipients_failed'] = 'SMTP Error: Adresy pøíjemcù nejsou správné ';
@@ -22,4 +22,3 @@ $PHPMAILER_LANG['recipients_failed'] = 'SMTP Error: Adresy pøíjemcù nejsou
//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.';
//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: ';
//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: ';
-?> \ No newline at end of file
diff --git a/library/phpmailer/language/phpmailer.lang-de.php b/library/phpmailer/language/phpmailer.lang-de.php
index b2a76ce1b5..ba17a92a95 100644
--- a/library/phpmailer/language/phpmailer.lang-de.php
+++ b/library/phpmailer/language/phpmailer.lang-de.php
@@ -14,7 +14,7 @@ $PHPMAILER_LANG['file_access'] = 'Zugriff auf folgende Datei fehlgeschl
$PHPMAILER_LANG['file_open'] = 'Datei Fehler: konnte folgende Datei nicht öffnen: ';
$PHPMAILER_LANG['from_failed'] = 'Die folgende Absenderadresse ist nicht korrekt: ';
$PHPMAILER_LANG['instantiate'] = 'Mail Funktion konnte nicht initialisiert werden.';
-$PHPMAILER_LANG['invalid_email'] = 'E-Mail wird nicht gesendet, die Adresse ist ungültig.';
+$PHPMAILER_LANG['invalid_address'] = 'E-Mail wird nicht gesendet, die Adresse ist ungültig.';
$PHPMAILER_LANG['mailer_not_supported'] = ' mailer wird nicht unterstützt.';
$PHPMAILER_LANG['provide_address'] = 'Bitte geben Sie mindestens eine Empfänger E-Mailadresse an.';
$PHPMAILER_LANG['recipients_failed'] = 'SMTP Fehler: Die folgenden Empfänger sind nicht korrekt: ';
@@ -22,4 +22,3 @@ $PHPMAILER_LANG['signing'] = 'Fehler beim Signieren: ';
$PHPMAILER_LANG['smtp_connect_failed'] = 'Verbindung zu SMTP Server fehlgeschlagen.';
$PHPMAILER_LANG['smtp_error'] = 'Fehler vom SMTP Server: ';
$PHPMAILER_LANG['variable_set'] = 'Kann Variable nicht setzen oder zurücksetzen: ';
-?> \ No newline at end of file
diff --git a/library/phpmailer/language/phpmailer.lang-dk.php b/library/phpmailer/language/phpmailer.lang-dk.php
index b26257316b..fdb0b17b85 100644
--- a/library/phpmailer/language/phpmailer.lang-dk.php
+++ b/library/phpmailer/language/phpmailer.lang-dk.php
@@ -15,7 +15,7 @@ $PHPMAILER_LANG['file_access'] = 'Ingen adgang til fil: ';
$PHPMAILER_LANG['file_open'] = 'Fil fejl: Kunne ikke åbne filen: ';
$PHPMAILER_LANG['from_failed'] = 'Følgende afsenderadresse er forkert: ';
$PHPMAILER_LANG['instantiate'] = 'Kunne ikke initialisere email funktionen.';
-//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: ';
+//$PHPMAILER_LANG['invalid_address'] = 'Not sending, email address is invalid: ';
$PHPMAILER_LANG['mailer_not_supported'] = ' mailer understøttes ikke.';
$PHPMAILER_LANG['provide_address'] = 'Du skal indtaste mindst en modtagers emailadresse.';
$PHPMAILER_LANG['recipients_failed'] = 'SMTP fejl: Følgende modtagere er forkerte: ';
@@ -23,4 +23,3 @@ $PHPMAILER_LANG['recipients_failed'] = 'SMTP fejl: Følgende modtagere er for
//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.';
//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: ';
//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: ';
-?> \ No newline at end of file
diff --git a/library/phpmailer/language/phpmailer.lang-eo.php b/library/phpmailer/language/phpmailer.lang-eo.php
new file mode 100644
index 0000000000..799b331963
--- /dev/null
+++ b/library/phpmailer/language/phpmailer.lang-eo.php
@@ -0,0 +1,24 @@
+<?php
+/**
+* PHPMailer language file: refer to English translation for definitive list
+* Esperanto version
+*/
+
+$PHPMAILER_LANG['authenticate'] = 'Eraro de servilo SMTP : aŭtentigo malsukcesis.';
+$PHPMAILER_LANG['connect_host'] = 'Eraro de servilo SMTP : konektado al servilo malsukcesis.';
+$PHPMAILER_LANG['data_not_accepted'] = 'Eraro de servilo SMTP : neĝustaj datumoj.';
+$PHPMAILER_LANG['empty_message'] = 'Teksto de mesaĝo mankas.';
+$PHPMAILER_LANG['encoding'] = 'Nekonata kodoprezento: ';
+$PHPMAILER_LANG['execute'] = 'Lanĉi rulumadon ne eblis: ';
+$PHPMAILER_LANG['file_access'] = 'Aliro al dosiero ne sukcesis: ';
+$PHPMAILER_LANG['file_open'] = 'Eraro de dosiero: malfermo neeblas: ';
+$PHPMAILER_LANG['from_failed'] = 'Jena adreso de sendinto malsukcesis: ';
+$PHPMAILER_LANG['instantiate'] = 'Genero de retmesaĝa funkcio neeblis.';
+$PHPMAILER_LANG['invalid_address'] = 'Retadreso ne validas: ';
+$PHPMAILER_LANG['mailer_not_supported'] = ' mesaĝilo ne subtenata.';
+$PHPMAILER_LANG['provide_address'] = 'Vi devas tajpi almenaŭ unu recevontan retadreson.';
+$PHPMAILER_LANG['recipients_failed'] = 'Eraro de servilo SMTP : la jenaj poŝtrecivuloj kaŭzis eraron: ';
+$PHPMAILER_LANG['signing'] = 'Eraro de subskribo: ';
+$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP konektado malsukcesis.';
+$PHPMAILER_LANG['smtp_error'] = 'Eraro de servilo SMTP : ';
+$PHPMAILER_LANG['variable_set'] = 'Variablo ne pravalorizeblas aŭ ne repravalorizeblas: ';
diff --git a/library/phpmailer/language/phpmailer.lang-es.php b/library/phpmailer/language/phpmailer.lang-es.php
index 69b6817482..b81520f285 100644
--- a/library/phpmailer/language/phpmailer.lang-es.php
+++ b/library/phpmailer/language/phpmailer.lang-es.php
@@ -3,24 +3,24 @@
* PHPMailer language file: refer to English translation for definitive list
* Spanish version
* Versión en español
+* Edited by Matt Sturdy - matt.sturdy@gmail.com
*/
$PHPMAILER_LANG['authenticate'] = 'Error SMTP: No se pudo autentificar.';
-$PHPMAILER_LANG['connect_host'] = 'Error SMTP: No puedo conectar al servidor SMTP.';
+$PHPMAILER_LANG['connect_host'] = 'Error SMTP: No se pudo conectar al servidor SMTP.';
$PHPMAILER_LANG['data_not_accepted'] = 'Error SMTP: Datos no aceptados.';
-//$PHPMAILER_LANG['empty_message'] = 'Message body empty';
+$PHPMAILER_LANG['empty_message'] = 'Cuerpo del mensaje vacío';
$PHPMAILER_LANG['encoding'] = 'Codificación desconocida: ';
-$PHPMAILER_LANG['execute'] = 'No puedo ejecutar: ';
-$PHPMAILER_LANG['file_access'] = 'No puedo acceder al archivo: ';
-$PHPMAILER_LANG['file_open'] = 'Error de Archivo: No puede abrir el archivo: ';
+$PHPMAILER_LANG['execute'] = 'No se pudo ejecutar: ';
+$PHPMAILER_LANG['file_access'] = 'No se pudo acceder al archivo: ';
+$PHPMAILER_LANG['file_open'] = 'Error de Archivo: No se pudo abrir el archivo: ';
$PHPMAILER_LANG['from_failed'] = 'La(s) siguiente(s) direcciones de remitente fallaron: ';
-$PHPMAILER_LANG['instantiate'] = 'No pude crear una instancia de la función Mail.';
-//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: ';
+$PHPMAILER_LANG['instantiate'] = 'No se pudo crear una instancia de la función Mail.';
+$PHPMAILER_LANG['invalid_address'] = 'No se pudo enviar: dirección de email inválido: ';
$PHPMAILER_LANG['mailer_not_supported'] = ' mailer no está soportado.';
-$PHPMAILER_LANG['provide_address'] = 'Debe proveer al menos una dirección de email como destinatario.';
-$PHPMAILER_LANG['recipients_failed'] = 'Error SMTP: Los siguientes destinatarios fallaron: ';
+$PHPMAILER_LANG['provide_address'] = 'Debe proveer al menos una dirección de email como destino.';
+$PHPMAILER_LANG['recipients_failed'] = 'Error SMTP: Los siguientes destinos fallaron: ';
$PHPMAILER_LANG['signing'] = 'Error al firmar: ';
-//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.';
-//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: ';
-//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: ';
-?> \ No newline at end of file
+$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() se falló.';
+$PHPMAILER_LANG['smtp_error'] = 'Error del servidor SMTP: ';
+$PHPMAILER_LANG['variable_set'] = 'No se pudo ajustar o reajustar la variable: ';
diff --git a/library/phpmailer/language/phpmailer.lang-et.php b/library/phpmailer/language/phpmailer.lang-et.php
index cf61779b08..eee4e58e88 100644
--- a/library/phpmailer/language/phpmailer.lang-et.php
+++ b/library/phpmailer/language/phpmailer.lang-et.php
@@ -3,24 +3,24 @@
* PHPMailer language file: refer to English translation for definitive list
* Estonian Version
* By Indrek Päri
+* Revised By Elan Ruusamäe <glen@delfi.ee>
*/
$PHPMAILER_LANG['authenticate'] = 'SMTP Viga: Autoriseerimise viga.';
$PHPMAILER_LANG['connect_host'] = 'SMTP Viga: Ei õnnestunud luua ühendust SMTP serveriga.';
$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Viga: Vigased andmed.';
-//$PHPMAILER_LANG['empty_message'] = 'Message body empty';
-$PHPMAILER_LANG['encoding'] = 'Tundmatu Unknown kodeering: ';
+$PHPMAILER_LANG['empty_message'] = 'Tühi kirja sisu';
+$PHPMAILER_LANG["encoding"] = 'Tundmatu kodeering: ';
$PHPMAILER_LANG['execute'] = 'Tegevus ebaõnnestus: ';
$PHPMAILER_LANG['file_access'] = 'Pole piisavalt õiguseid järgneva faili avamiseks: ';
$PHPMAILER_LANG['file_open'] = 'Faili Viga: Faili avamine ebaõnnestus: ';
$PHPMAILER_LANG['from_failed'] = 'Järgnev saatja e-posti aadress on vigane: ';
$PHPMAILER_LANG['instantiate'] = 'mail funktiooni käivitamine ebaõnnestus.';
-//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: ';
+$PHPMAILER_LANG['invalid_address'] = 'Saatmine peatatud, e-posti address vigane: ';
$PHPMAILER_LANG['provide_address'] = 'Te peate määrama vähemalt ühe saaja e-posti aadressi.';
$PHPMAILER_LANG['mailer_not_supported'] = ' maileri tugi puudub.';
$PHPMAILER_LANG['recipients_failed'] = 'SMTP Viga: Järgnevate saajate e-posti aadressid on vigased: ';
-//$PHPMAILER_LANG['signing'] = 'Signing Error: ';
-//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.';
-//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: ';
-//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: ';
-?> \ No newline at end of file
+$PHPMAILER_LANG["signing"] = 'Viga allkirjastamisel: ';
+$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() ebaõnnestus.';
+$PHPMAILER_LANG['smtp_error'] = 'SMTP serveri viga: ';
+$PHPMAILER_LANG['variable_set'] = 'Ei õnnestunud määrata või lähtestada muutujat: ';
diff --git a/library/phpmailer/language/phpmailer.lang-fi.php b/library/phpmailer/language/phpmailer.lang-fi.php
index 12a845aad6..16a02e1380 100644
--- a/library/phpmailer/language/phpmailer.lang-fi.php
+++ b/library/phpmailer/language/phpmailer.lang-fi.php
@@ -15,7 +15,7 @@ $PHPMAILER_LANG['file_access'] = 'Seuraavaan tiedostoon ei ole oikeuksi
$PHPMAILER_LANG['file_open'] = 'Tiedostovirhe: Ei voida avata tiedostoa: ';
$PHPMAILER_LANG['from_failed'] = 'Seuraava lähettäjän osoite on virheellinen: ';
$PHPMAILER_LANG['instantiate'] = 'mail-funktion luonti epäonnistui.';
-//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: ';
+//$PHPMAILER_LANG['invalid_address'] = 'Not sending, email address is invalid: ';
$PHPMAILER_LANG['mailer_not_supported'] = 'postivälitintyyppiä ei tueta.';
$PHPMAILER_LANG['provide_address'] = 'Aseta vähintään yksi vastaanottajan sähk&ouml;postiosoite.';
$PHPMAILER_LANG['recipients_failed'] = 'SMTP-virhe: seuraava vastaanottaja osoite on virheellinen.';
@@ -24,4 +24,3 @@ $PHPMAILER_LANG['encoding'] = 'Tuntematon koodaustyyppi: ';
//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.';
//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: ';
//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: ';
-?> \ No newline at end of file
diff --git a/library/phpmailer/language/phpmailer.lang-fo.php b/library/phpmailer/language/phpmailer.lang-fo.php
index 6bd9b0a213..fc5d6d5654 100644
--- a/library/phpmailer/language/phpmailer.lang-fo.php
+++ b/library/phpmailer/language/phpmailer.lang-fo.php
@@ -16,7 +16,7 @@ $PHPMAILER_LANG['file_access'] = 'Kundi ikki tilganga fílu: ';
$PHPMAILER_LANG['file_open'] = 'Fílu feilur: Kundi ikki opna fílu: ';
$PHPMAILER_LANG['from_failed'] = 'fylgjandi Frá/From adressa miseydnaðist: ';
$PHPMAILER_LANG['instantiate'] = 'Kuni ikki instantiera mail funktión.';
-//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: ';
+//$PHPMAILER_LANG['invalid_address'] = 'Not sending, email address is invalid: ';
$PHPMAILER_LANG['mailer_not_supported'] = ' er ikki supporterað.';
$PHPMAILER_LANG['provide_address'] = 'Tú skal uppgeva minst móttakara-emailadressu(r).';
$PHPMAILER_LANG['recipients_failed'] = 'SMTP Feilur: Fylgjandi móttakarar miseydnaðust: ';
@@ -24,4 +24,3 @@ $PHPMAILER_LANG['recipients_failed'] = 'SMTP Feilur: Fylgjandi móttakarar mi
//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.';
//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: ';
//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: ';
-?> \ No newline at end of file
diff --git a/library/phpmailer/language/phpmailer.lang-fr.php b/library/phpmailer/language/phpmailer.lang-fr.php
index c99ac3caf9..b8dfc7743d 100644
--- a/library/phpmailer/language/phpmailer.lang-fr.php
+++ b/library/phpmailer/language/phpmailer.lang-fr.php
@@ -4,22 +4,21 @@
* French Version
*/
-$PHPMAILER_LANG['authenticate'] = 'Erreur SMTP : Echec de l\'authentification.';
-$PHPMAILER_LANG['connect_host'] = 'Erreur SMTP : Impossible de se connecter au serveur SMTP.';
-$PHPMAILER_LANG['data_not_accepted'] = 'Erreur SMTP : Données incorrects.';
-$PHPMAILER_LANG['empty_message'] = 'Corps de message vide';
-$PHPMAILER_LANG['encoding'] = 'Encodage inconnu : ';
-$PHPMAILER_LANG['execute'] = 'Impossible de lancer l\'exécution : ';
-$PHPMAILER_LANG['file_access'] = 'Impossible d\'accéder au fichier : ';
-$PHPMAILER_LANG['file_open'] = 'Erreur Fichier : ouverture impossible : ';
-$PHPMAILER_LANG['from_failed'] = 'L\'adresse d\'expéditeur suivante a échouée : ';
+$PHPMAILER_LANG['authenticate'] = 'Erreur SMTP : échec de l\'authentification.';
+$PHPMAILER_LANG['connect_host'] = 'Erreur SMTP : impossible de se connecter au serveur SMTP.';
+$PHPMAILER_LANG['data_not_accepted'] = 'Erreur SMTP : données incorrectes.';
+$PHPMAILER_LANG['empty_message'] = 'Corps de message vide.';
+$PHPMAILER_LANG['encoding'] = 'Encodage inconnu: ';
+$PHPMAILER_LANG['execute'] = 'Impossible de lancer l\'exécution: ';
+$PHPMAILER_LANG['file_access'] = 'Impossible d\'accéder au fichier: ';
+$PHPMAILER_LANG['file_open'] = 'Erreur de fichier : ouverture impossible: ';
+$PHPMAILER_LANG['from_failed'] = 'L\'adresse d\'expéditeur suivante a échouée: ';
$PHPMAILER_LANG['instantiate'] = 'Impossible d\'instancier la fonction mail.';
-//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: ';
+$PHPMAILER_LANG['invalid_address'] = 'L\'adresse courriel n\'est pas valide: ';
$PHPMAILER_LANG['mailer_not_supported'] = ' client de messagerie non supporté.';
$PHPMAILER_LANG['provide_address'] = 'Vous devez fournir au moins une adresse de destinataire.';
-$PHPMAILER_LANG['recipients_failed'] = 'Erreur SMTP : Les destinataires suivants sont en erreur : ';
-//$PHPMAILER_LANG['signing'] = 'Signing Error: ';
-//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.';
-//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: ';
-//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: ';
-?> \ No newline at end of file
+$PHPMAILER_LANG['recipients_failed'] = 'Erreur SMTP : les destinataires suivants sont en erreur: ';
+$PHPMAILER_LANG['signing'] = 'Erreur de signature: ';
+$PHPMAILER_LANG['smtp_connect_failed'] = 'Échec de la connexion SMTP.';
+$PHPMAILER_LANG['smtp_error'] = 'Erreur du serveur SMTP: ';
+$PHPMAILER_LANG['variable_set'] = 'Ne peut initialiser ou réinitialiser une variable: ';
diff --git a/library/phpmailer/language/phpmailer.lang-he.php b/library/phpmailer/language/phpmailer.lang-he.php
new file mode 100644
index 0000000000..e30b596d60
--- /dev/null
+++ b/library/phpmailer/language/phpmailer.lang-he.php
@@ -0,0 +1,25 @@
+<?php
+/**
+* PHPMailer language file: refer to English translation for definitive list
+* Hebrew Version, UTF-8
+* by : Ronny Sherer <ronny@hoojima.com>
+*/
+
+$PHPMAILER_LANG['authenticate'] = 'שגיאת SMTP: פעולת האימות נכשלה.';
+$PHPMAILER_LANG['connect_host'] = 'שגיאת SMTP: לא הצלחתי להתחבר לשרת SMTP.';
+$PHPMAILER_LANG['data_not_accepted'] = 'שגיאת SMTP: מידע לא התקבל.';
+$PHPMAILER_LANG['empty_message'] = 'גוף ההודעה ריק';
+$PHPMAILER_LANG['invalid_address'] = 'כתובת שגויה';
+$PHPMAILER_LANG['encoding'] = 'קידוד לא מוכר: ';
+$PHPMAILER_LANG['execute'] = 'לא הצלחתי להפעיל את: ';
+$PHPMAILER_LANG['file_access'] = 'לא ניתן לגשת לקובץ: ';
+$PHPMAILER_LANG['file_open'] = 'שגיאת קובץ: לא ניתן לגשת לקובץ: ';
+$PHPMAILER_LANG['from_failed'] = 'כתובות הנמענים הבאות נכשלו: ';
+$PHPMAILER_LANG['instantiate'] = 'לא הצלחתי להפעיל את פונקציית המייל.';
+$PHPMAILER_LANG['mailer_not_supported'] = ' אינה נתמכת.';
+$PHPMAILER_LANG['provide_address'] = 'חובה לספק לפחות כתובת אחת של מקבל המייל.';
+$PHPMAILER_LANG['recipients_failed'] = 'שגיאת SMTP: הנמענים הבאים נכשלו: ';
+$PHPMAILER_LANG['signing'] = 'שגיאת חתימה: ';
+$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.';
+$PHPMAILER_LANG['smtp_error'] = 'שגיאת שרת SMTP: ';
+$PHPMAILER_LANG['variable_set'] = 'לא ניתן לקבוע או לשנות את המשתנה: ';
diff --git a/library/phpmailer/language/phpmailer.lang-hu.php b/library/phpmailer/language/phpmailer.lang-hu.php
index caca0b50f1..d8d1926796 100644
--- a/library/phpmailer/language/phpmailer.lang-hu.php
+++ b/library/phpmailer/language/phpmailer.lang-hu.php
@@ -1,25 +1,24 @@
<?php
/**
* PHPMailer language file: refer to English translation for definitive list
-* Hungarian Version
+* Hungarian Version by @dominicus-75
*/
-$PHPMAILER_LANG['authenticate'] = 'SMTP Hiba: Sikertelen autentikáció.';
-$PHPMAILER_LANG['connect_host'] = 'SMTP Hiba: Nem tudtam csatlakozni az SMTP host-hoz.';
-$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Hiba: Nem elfogadható adat.';
-//$PHPMAILER_LANG['empty_message'] = 'Message body empty';
+$PHPMAILER_LANG['authenticate'] = 'SMTP hiba: az azonosítás sikertelen.';
+$PHPMAILER_LANG['connect_host'] = 'SMTP hiba: nem lehet kapcsolódni az SMTP-szerverhez.';
+$PHPMAILER_LANG['data_not_accepted'] = 'SMTP hiba: adatok visszautasítva.';
+$PHPMAILER_LANG['empty_message'] = 'Üres az üzenettörzs.';
$PHPMAILER_LANG['encoding'] = 'Ismeretlen kódolás: ';
-$PHPMAILER_LANG['execute'] = 'Nem tudtam végrehajtani: ';
-$PHPMAILER_LANG['file_access'] = 'Nem sikerült elérni a következõ fájlt: ';
-$PHPMAILER_LANG['file_open'] = 'Fájl Hiba: Nem sikerült megnyitni a következõ fájlt: ';
-$PHPMAILER_LANG['from_failed'] = 'Az alábbi Feladó cím hibás: ';
-$PHPMAILER_LANG['instantiate'] = 'Nem sikerült példányosítani a mail funkciót.';
-//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: ';
-$PHPMAILER_LANG['provide_address'] = 'Meg kell adnod legalább egy címzett email címet.';
-$PHPMAILER_LANG['mailer_not_supported'] = ' levelezõ nem támogatott.';
-$PHPMAILER_LANG['recipients_failed'] = 'SMTP Hiba: Az alábbi címzettek hibásak: ';
-//$PHPMAILER_LANG['signing'] = 'Signing Error: ';
-//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.';
-//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: ';
-//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: ';
-?> \ No newline at end of file
+$PHPMAILER_LANG['execute'] = 'Nem lehet végrehajtani: ';
+$PHPMAILER_LANG['file_access'] = 'A következő fájl nem elérhető: ';
+$PHPMAILER_LANG['file_open'] = 'Fájl hiba: a következő fájlt nem lehet megnyitni: ';
+$PHPMAILER_LANG['from_failed'] = 'A feladóként megadott következő cím hibás: ';
+$PHPMAILER_LANG['instantiate'] = 'A PHP mail() függvényt nem sikerült végrehajtani.';
+$PHPMAILER_LANG['invalid_address'] = 'Érvénytelen cím: ';
+$PHPMAILER_LANG['mailer_not_supported'] = ' a mailer-osztály nem támogatott.';
+$PHPMAILER_LANG['provide_address'] = 'Legalább egy címzettet fel kell tüntetni.';
+$PHPMAILER_LANG['recipients_failed'] = 'SMTP hiba: a címzettként megadott következő címek hibásak: ';
+$PHPMAILER_LANG['signing'] = 'Hibás aláírás: ';
+$PHPMAILER_LANG['smtp_connect_failed'] = 'Hiba az SMTP-kapcsolatban.';
+$PHPMAILER_LANG['smtp_error'] = 'SMTP-szerver hiba: ';
+$PHPMAILER_LANG['variable_set'] = 'A következő változók beállítása nem sikerült: ';
diff --git a/library/phpmailer/language/phpmailer.lang-it.php b/library/phpmailer/language/phpmailer.lang-it.php
index fc1fcb8d2e..27ab0ead00 100644
--- a/library/phpmailer/language/phpmailer.lang-it.php
+++ b/library/phpmailer/language/phpmailer.lang-it.php
@@ -3,25 +3,24 @@
* PHPMailer language file: refer to English translation for definitive list
* Italian version
* @package PHPMailer
-* @author Ilias Bartolini <brain79@inwind.it>
+* @author Ilias Bartolini <brain79@inwind.it>, Stefano Sabatini <sabas88@gmail.com>
*/
$PHPMAILER_LANG['authenticate'] = 'SMTP Error: Impossibile autenticarsi.';
$PHPMAILER_LANG['connect_host'] = 'SMTP Error: Impossibile connettersi all\'host SMTP.';
-$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Error: Data non accettati dal server.';
-//$PHPMAILER_LANG['empty_message'] = 'Message body empty';
-$PHPMAILER_LANG['encoding'] = 'Encoding set dei caratteri sconosciuto: ';
+$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Error: Dati non accettati dal server.';
+$PHPMAILER_LANG['empty_message'] = 'Il corpo del messaggio è vuoto';
+$PHPMAILER_LANG['encoding'] = 'Codifica dei caratteri sconosciuta: ';
$PHPMAILER_LANG['execute'] = 'Impossibile eseguire l\'operazione: ';
$PHPMAILER_LANG['file_access'] = 'Impossibile accedere al file: ';
$PHPMAILER_LANG['file_open'] = 'File Error: Impossibile aprire il file: ';
$PHPMAILER_LANG['from_failed'] = 'I seguenti indirizzi mittenti hanno generato errore: ';
$PHPMAILER_LANG['instantiate'] = 'Impossibile istanziare la funzione mail';
-//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: ';
+$PHPMAILER_LANG['invalid_address'] = 'Impossibile inviare, l\'indirizzo email non è valido: ';
$PHPMAILER_LANG['provide_address'] = 'Deve essere fornito almeno un indirizzo ricevente';
$PHPMAILER_LANG['mailer_not_supported'] = 'Mailer non supportato';
-$PHPMAILER_LANG['recipients_failed'] = 'SMTP Error: I seguenti indirizzi destinatari hanno generato errore: ';
-//$PHPMAILER_LANG['signing'] = 'Signing Error: ';
-//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.';
-//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: ';
-//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: ';
-?> \ No newline at end of file
+$PHPMAILER_LANG['recipients_failed'] = 'SMTP Error: I seguenti indirizzi destinatari hanno generato un errore: ';
+$PHPMAILER_LANG['signing'] = 'Errore nella firma: ';
+$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() fallita.';
+$PHPMAILER_LANG['smtp_error'] = 'Errore del server SMTP: ';
+$PHPMAILER_LANG['variable_set'] = 'Impossibile impostare o resettare la variabile: ';
diff --git a/library/phpmailer/language/phpmailer.lang-ja.php b/library/phpmailer/language/phpmailer.lang-ja.php
index 63cfb23b6a..ca6de909da 100644
--- a/library/phpmailer/language/phpmailer.lang-ja.php
+++ b/library/phpmailer/language/phpmailer.lang-ja.php
@@ -3,6 +3,7 @@
* PHPMailer language file: refer to English translation for definitive list
* Japanese Version
* By Mitsuhiro Yoshida - http://mitstek.com/
+* Modified by Yoshi Sakai - http://bluemooninc.jp/
*/
$PHPMAILER_LANG['authenticate'] = 'SMTPエラー: 認証できませんでした。';
@@ -13,9 +14,9 @@ $PHPMAILER_LANG['encoding'] = '不明なエンコーディング: ';
$PHPMAILER_LANG['execute'] = '実行できませんでした: ';
$PHPMAILER_LANG['file_access'] = 'ファイルにアクセスできません: ';
$PHPMAILER_LANG['file_open'] = 'ファイルエラー: ファイルを開けません: ';
-$PHPMAILER_LANG['from_failed'] = '次のFromアドレスに間違いがあります: ';
+$PHPMAILER_LANG['from_failed'] = 'Fromアドレスを登録する際にエラーが発生しました: ';
$PHPMAILER_LANG['instantiate'] = 'メール関数が正常に動作しませんでした。';
-//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: ';
+//$PHPMAILER_LANG['invalid_address'] = 'Not sending, email address is invalid: ';
$PHPMAILER_LANG['provide_address'] = '少なくとも1つメールアドレスを 指定する必要があります。';
$PHPMAILER_LANG['mailer_not_supported'] = ' メーラーがサポートされていません。';
$PHPMAILER_LANG['recipients_failed'] = 'SMTPエラー: 次の受信者アドレスに 間違いがあります: ';
@@ -23,4 +24,3 @@ $PHPMAILER_LANG['recipients_failed'] = 'SMTPエラー: 次の受信者アドレ
//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.';
//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: ';
//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: ';
-?> \ No newline at end of file
diff --git a/library/phpmailer/language/phpmailer.lang-lt.php b/library/phpmailer/language/phpmailer.lang-lt.php
new file mode 100644
index 0000000000..5dba58a932
--- /dev/null
+++ b/library/phpmailer/language/phpmailer.lang-lt.php
@@ -0,0 +1,24 @@
+<?php
+/**
+* PHPMailer language file: refer to English translation for definitive list
+* Lithuanian version by Dainius Kaupaitis <dk@sum.lt>
+*/
+
+$PHPMAILER_LANG['authenticate'] = 'SMTP klaida: autentifikacija nepavyko.';
+$PHPMAILER_LANG['connect_host'] = 'SMTP klaida: nepavyksta prisijungti prie SMTP stoties.';
+$PHPMAILER_LANG['data_not_accepted'] = 'SMTP klaida: duomenys nepriimti.';
+$PHPMAILER_LANG['empty_message'] = 'Laiško turinys tuščias';
+$PHPMAILER_LANG['encoding'] = 'Neatpažinta koduotė: ';
+$PHPMAILER_LANG['execute'] = 'Nepavyko įvykdyti komandos: ';
+$PHPMAILER_LANG['file_access'] = 'Byla nepasiekiama: ';
+$PHPMAILER_LANG['file_open'] = 'Bylos klaida: Nepavyksta atidaryti: ';
+$PHPMAILER_LANG['from_failed'] = 'Neteisingas siuntėjo adresas: ';
+$PHPMAILER_LANG['instantiate'] = 'Nepavyko paleisti mail funkcijos.';
+$PHPMAILER_LANG['invalid_address'] = 'Neteisingas adresas';
+$PHPMAILER_LANG['mailer_not_supported'] = ' pašto stotis nepalaikoma.';
+$PHPMAILER_LANG['provide_address'] = 'Nurodykite bent vieną gavėjo adresą.';
+$PHPMAILER_LANG['recipients_failed'] = 'SMTP klaida: nepavyko išsiųsti šiems gavėjams: ';
+$PHPMAILER_LANG['signing'] = 'Prisijungimo klaida: ';
+$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP susijungimo klaida';
+$PHPMAILER_LANG['smtp_error'] = 'SMTP stoties klaida: ';
+$PHPMAILER_LANG['variable_set'] = 'Nepavyko priskirti reikšmės kintamajam: ';
diff --git a/library/phpmailer/language/phpmailer.lang-nl.php b/library/phpmailer/language/phpmailer.lang-nl.php
index d2c380b09d..c86d7699bf 100644
--- a/library/phpmailer/language/phpmailer.lang-nl.php
+++ b/library/phpmailer/language/phpmailer.lang-nl.php
@@ -1,25 +1,24 @@
<?php
/**
-* PHPMailer language file: refer to English translation for definitive list
-* Dutch Version
+* PHPMailer language file: refer to class.phpmailer.php for definitive list.
+* Dutch Version by Tuxion <team@tuxion.nl>
*/
-$PHPMAILER_LANG['authenticate'] = 'SMTP Fout: authenticatie mislukt.';
-$PHPMAILER_LANG['connect_host'] = 'SMTP Fout: Kon niet verbinden met SMTP host.';
-$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Fout: Data niet geaccepteerd.';
-//$PHPMAILER_LANG['empty_message'] = 'Message body empty';
-$PHPMAILER_LANG['encoding'] = 'Onbekende codering: ';
-$PHPMAILER_LANG['execute'] = 'Kon niet uitvoeren: ';
-$PHPMAILER_LANG['file_access'] = 'Kreeg geen toegang tot bestand: ';
-$PHPMAILER_LANG['file_open'] = 'Bestandsfout: Kon bestand niet openen: ';
-$PHPMAILER_LANG['from_failed'] = 'De volgende afzender adressen zijn mislukt: ';
-$PHPMAILER_LANG['instantiate'] = 'Kon mail functie niet initialiseren.';
-//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: ';
-$PHPMAILER_LANG['provide_address'] = 'Er moet tenmiste één ontvanger emailadres opgegeven worden.';
-$PHPMAILER_LANG['mailer_not_supported'] = ' mailer wordt niet ondersteund.';
-$PHPMAILER_LANG['recipients_failed'] = 'SMTP Fout: De volgende ontvangers zijn mislukt: ';
-//$PHPMAILER_LANG['signing'] = 'Signing Error: ';
-//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.';
-//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: ';
-//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: ';
-?> \ No newline at end of file
+$PHPMAILER_LANG['authenticate'] = 'SMTP-fout: authenticatie mislukt.';//SMTP Error: Could not authenticate.
+$PHPMAILER_LANG['connect_host'] = 'SMTP-fout: kon niet verbinden met SMTP-host.';//SMTP Error: Could not connect to SMTP host.
+$PHPMAILER_LANG['data_not_accepted'] = 'SMTP-fout: data niet geaccepteerd.';//SMTP Error: Data not accepted.
+$PHPMAILER_LANG['empty_message'] = 'Berichttekst is leeg';//Message body empty
+$PHPMAILER_LANG['encoding'] = 'Onbekende codering: ';//Unknown encoding:
+$PHPMAILER_LANG['execute'] = 'Kon niet uitvoeren: ';//Could not execute:
+$PHPMAILER_LANG['file_access'] = 'Kreeg geen toegang tot bestand: ';//Could not access file:
+$PHPMAILER_LANG['file_open'] = 'Bestandsfout: kon bestand niet openen: ';//File Error: Could not open file:
+$PHPMAILER_LANG['from_failed'] = 'Het volgende afzendersadres is mislukt: ';//The following From address failed:
+$PHPMAILER_LANG['instantiate'] = 'Kon mailfunctie niet initialiseren.';//Could not instantiate mail function.
+$PHPMAILER_LANG['invalid_address'] = 'Ongeldig adres';//Invalid address
+$PHPMAILER_LANG['mailer_not_supported'] = ' mailer wordt niet ondersteund.';// mailer is not supported.
+$PHPMAILER_LANG['provide_address'] = 'Er moet minstens één ontvanger worden opgegeven.';//You must provide at least one recipient email address.
+$PHPMAILER_LANG['recipients_failed'] = 'SMTP-fout: de volgende ontvangers zijn mislukt: ';//SMTP Error: The following recipients failed:
+$PHPMAILER_LANG['signing'] = 'Signeerfout: ';//Signing Error:
+$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Verbinding mislukt.';
+$PHPMAILER_LANG['smtp_error'] = 'SMTP-serverfout: ';//SMTP server error:
+$PHPMAILER_LANG['variable_set'] = 'Kan de volgende variablen niet instellen of resetten: ';//Cannot set or reset variable:
diff --git a/library/phpmailer/language/phpmailer.lang-no.php b/library/phpmailer/language/phpmailer.lang-no.php
index 65cb884399..e6975203e3 100644
--- a/library/phpmailer/language/phpmailer.lang-no.php
+++ b/library/phpmailer/language/phpmailer.lang-no.php
@@ -7,19 +7,18 @@
$PHPMAILER_LANG['authenticate'] = 'SMTP Feil: Kunne ikke authentisere.';
$PHPMAILER_LANG['connect_host'] = 'SMTP Feil: Kunne ikke koble til SMTP host.';
$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Feil: Data ble ikke akseptert.';
-//$PHPMAILER_LANG['empty_message'] = 'Message body empty';
-$PHPMAILER_LANG['encoding'] = 'Ukjent encoding: ';
+$PHPMAILER_LANG['empty_message'] = 'Meldingsinnholdet er tomt';
+$PHPMAILER_LANG['encoding'] = 'Ukjent tegnkoding: ';
$PHPMAILER_LANG['execute'] = 'Kunne ikke utføre: ';
-$PHPMAILER_LANG['file_access'] = 'Kunne ikke få tilgang til filen: ';
+$PHPMAILER_LANG['file_access'] = 'Får ikke tilgang til filen: ';
$PHPMAILER_LANG['file_open'] = 'Fil feil: Kunne ikke åpne filen: ';
-$PHPMAILER_LANG['from_failed'] = 'Følgende Fra feilet: ';
-$PHPMAILER_LANG['instantiate'] = 'Kunne ikke instantiate mail funksjonen.';
-//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: ';
-$PHPMAILER_LANG['provide_address'] = 'Du må ha med minst en mottager adresse.';
+$PHPMAILER_LANG['from_failed'] = 'Følgende avsenderadresse feilet: ';
+$PHPMAILER_LANG['instantiate'] = 'Kunne ikke initialisere mailfunksjonen.';
+$PHPMAILER_LANG['invalid_address'] = 'Meldingen ble ikke sendt, følgende adresse er ugyldig: ';
+$PHPMAILER_LANG['provide_address'] = 'Du må angi minst en mottakeradresse.';
$PHPMAILER_LANG['mailer_not_supported'] = ' mailer er ikke supportert.';
$PHPMAILER_LANG['recipients_failed'] = 'SMTP Feil: Følgende mottagere feilet: ';
-//$PHPMAILER_LANG['signing'] = 'Signing Error: ';
-//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.';
-//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: ';
-//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: ';
-?> \ No newline at end of file
+$PHPMAILER_LANG['signing'] = 'Signeringsfeil: ';
+$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() feilet.';
+$PHPMAILER_LANG['smtp_error'] = 'SMTP-serverfeil: ';
+$PHPMAILER_LANG['variable_set'] = 'Kan ikke sette eller resette variabelen: '; \ No newline at end of file
diff --git a/library/phpmailer/language/phpmailer.lang-pl.php b/library/phpmailer/language/phpmailer.lang-pl.php
index 6e9a82fda6..5a4ad38318 100644
--- a/library/phpmailer/language/phpmailer.lang-pl.php
+++ b/library/phpmailer/language/phpmailer.lang-pl.php
@@ -3,22 +3,22 @@
* PHPMailer language file: refer to English translation for definitive list
* Polish Version
*/
-$PHPMAILER_LANG = array(
- 'provide_address' => 'Należy podać prawidłowy adres email Odbiorcy.',
- 'mailer_not_supported' => 'Wybrana metoda wysyłania wiadomości nie jest obsługiwana.',
- 'execute' => 'Nie można uruchomić: ',
- 'instantiate' => 'Nie można wywołać funkcji mail(). Sprawdź konfigurację serwera.',
- 'authenticate' => 'Błąd SMTP: Nie można przeprowadzić uwierzytelniania.',
- 'from_failed' => 'Następujący adres Nadawcy jest jest nieprawidłowy: ',
- 'recipients_failed' => 'Błąd SMTP: Następujący odbiorcy są nieprawidłowi: ',
- 'data_not_accepted' => 'Błąd SMTP: Dane nie zostały przyjęte.',
- 'connect_host' => 'Błąd SMTP: Nie można połączyć się z wybranym hostem.',
- 'file_access' => 'Brak dostępu do pliku: ',
- 'file_open' => 'Nie można otworzyć pliku: ',
- 'encoding' => 'Nieznany sposób kodowania znaków: ',
- 'signing' => 'Błąd logowania: ',
- 'smtp_error' => 'Błąd serwera SMTP: ',
- 'empty_message' => 'Pusta treść wiadomości',
- 'invalid_address' => 'Adres email jest nieprawidłowy',
- 'variable_set' => 'Nie można ustawić lub zresetować zmiennej: '
-); \ No newline at end of file
+
+$PHPMAILER_LANG['authenticate'] = 'Błąd SMTP: Nie można przeprowadzić autentykacji.';
+$PHPMAILER_LANG['connect_host'] = 'Błąd SMTP: Nie można połączyć się z wybranym hostem.';
+$PHPMAILER_LANG['data_not_accepted'] = 'Błąd SMTP: Dane nie zostały przyjęte.';
+$PHPMAILER_LANG['empty_message'] = 'Wiadomość jest pusta.';
+$PHPMAILER_LANG['encoding'] = 'Nieznany sposób kodowania znaków: ';
+$PHPMAILER_LANG['execute'] = 'Nie można uruchomić: ';
+$PHPMAILER_LANG['file_access'] = 'Brak dostępu do pliku: ';
+$PHPMAILER_LANG['file_open'] = 'Nie można otworzyć pliku: ';
+$PHPMAILER_LANG['from_failed'] = 'Następujący adres Nadawcy jest nieprawidłowy: ';
+$PHPMAILER_LANG['instantiate'] = 'Nie można wywołać funkcji mail(). Sprawdź konfigurację serwera.';
+$PHPMAILER_LANG['invalid_address'] = 'Nie można wysłać wiadomości, następujący adres Odbiorcy jest nieprawidłowy: ';
+$PHPMAILER_LANG['provide_address'] = 'Należy podać prawidłowy adres email Odbiorcy.';
+$PHPMAILER_LANG['mailer_not_supported'] = 'Wybrana metoda wysyłki wiadomości nie jest obsługiwana.';
+$PHPMAILER_LANG['recipients_failed'] = 'Błąd SMTP: Następujący odbiorcy są nieprawidłowi: ';
+$PHPMAILER_LANG['signing'] = 'Błąd podpisywania wiadomości: ';
+$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() zakończone niepowodzeniem.';
+$PHPMAILER_LANG['smtp_error'] = 'Błąd SMTP: ';
+$PHPMAILER_LANG['variable_set'] = 'Nie można zmienić zmiennej: ';
diff --git a/library/phpmailer/language/phpmailer.lang-ro.php b/library/phpmailer/language/phpmailer.lang-ro.php
index f6aa922556..1727cef04a 100644
--- a/library/phpmailer/language/phpmailer.lang-ro.php
+++ b/library/phpmailer/language/phpmailer.lang-ro.php
@@ -16,7 +16,7 @@ $PHPMAILER_LANG['file_access'] = 'Nu pot accesa fisierul: ';
$PHPMAILER_LANG['file_open'] = 'Eroare de fisier: Nu pot deschide fisierul: ';
$PHPMAILER_LANG['from_failed'] = 'Urmatoarele adrese From au dat eroare: ';
$PHPMAILER_LANG['instantiate'] = 'Nu am putut instantia functia mail.';
-//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: ';
+//$PHPMAILER_LANG['invalid_address'] = 'Not sending, email address is invalid: ';
$PHPMAILER_LANG['mailer_not_supported'] = ' mailer nu este suportat.';
$PHPMAILER_LANG['provide_address'] = 'Trebuie sa adaugati cel putin un recipient (adresa de mail).';
$PHPMAILER_LANG['recipients_failed'] = 'Eroare SMTP: Urmatoarele adrese de mail au dat eroare: ';
@@ -24,4 +24,3 @@ $PHPMAILER_LANG['recipients_failed'] = 'Eroare SMTP: Urmatoarele adrese de ma
//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.';
//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: ';
//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: ';
-?> \ No newline at end of file
diff --git a/library/phpmailer/language/phpmailer.lang-ru.php b/library/phpmailer/language/phpmailer.lang-ru.php
index d6990525de..9e583dae05 100644
--- a/library/phpmailer/language/phpmailer.lang-ru.php
+++ b/library/phpmailer/language/phpmailer.lang-ru.php
@@ -7,19 +7,18 @@
$PHPMAILER_LANG['authenticate'] = 'Ошибка SMTP: ошибка авторизации.';
$PHPMAILER_LANG['connect_host'] = 'Ошибка SMTP: не удается подключиться к серверу SMTP.';
$PHPMAILER_LANG['data_not_accepted'] = 'Ошибка SMTP: данные не приняты.';
-//$PHPMAILER_LANG['empty_message'] = 'Message body empty';
$PHPMAILER_LANG['encoding'] = 'Неизвестный вид кодировки: ';
$PHPMAILER_LANG['execute'] = 'Невозможно выполнить команду: ';
$PHPMAILER_LANG['file_access'] = 'Нет доступа к файлу: ';
$PHPMAILER_LANG['file_open'] = 'Файловая ошибка: не удается открыть файл: ';
$PHPMAILER_LANG['from_failed'] = 'Неверный адрес отправителя: ';
$PHPMAILER_LANG['instantiate'] = 'Невозможно запустить функцию mail.';
-//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: ';
$PHPMAILER_LANG['provide_address'] = 'Пожалуйста, введите хотя бы один адрес e-mail получателя.';
$PHPMAILER_LANG['mailer_not_supported'] = ' - почтовый сервер не поддерживается.';
$PHPMAILER_LANG['recipients_failed'] = 'Ошибка SMTP: отправка по следующим адресам получателей не удалась: ';
-//$PHPMAILER_LANG['signing'] = 'Signing Error: ';
-//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.';
-//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: ';
-//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: ';
-?> \ No newline at end of file
+$PHPMAILER_LANG['empty_message'] = 'Пустое тело сообщения';
+$PHPMAILER_LANG['invalid_address'] = 'Не отослано, неправильный формат email адреса: ';
+$PHPMAILER_LANG['signing'] = 'Ошибка подписывания: ';
+$PHPMAILER_LANG['smtp_connect_failed'] = 'Ошибка соединения с SMTP-сервером';
+$PHPMAILER_LANG['smtp_error'] = 'Ошибка SMTP-сервера: ';
+$PHPMAILER_LANG['variable_set'] = 'Невозможно установить или переустановить переменную: ';
diff --git a/library/phpmailer/language/phpmailer.lang-se.php b/library/phpmailer/language/phpmailer.lang-se.php
index 67e05f59c6..65d197995c 100644
--- a/library/phpmailer/language/phpmailer.lang-se.php
+++ b/library/phpmailer/language/phpmailer.lang-se.php
@@ -15,7 +15,7 @@ $PHPMAILER_LANG['file_access'] = 'Ingen åtkomst till fil: ';
$PHPMAILER_LANG['file_open'] = 'Fil fel: Kunde inte öppna fil: ';
$PHPMAILER_LANG['from_failed'] = 'Följande avsändaradress är felaktig: ';
$PHPMAILER_LANG['instantiate'] = 'Kunde inte initiera e-postfunktion.';
-//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: ';
+//$PHPMAILER_LANG['invalid_address'] = 'Not sending, email address is invalid: ';
$PHPMAILER_LANG['provide_address'] = 'Du måste ange minst en mottagares e-postadress.';
$PHPMAILER_LANG['mailer_not_supported'] = ' mailer stöds inte.';
$PHPMAILER_LANG['recipients_failed'] = 'SMTP fel: Följande mottagare är felaktig: ';
@@ -23,4 +23,3 @@ $PHPMAILER_LANG['recipients_failed'] = 'SMTP fel: Följande mottagare är fel
//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.';
//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: ';
//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: ';
-?> \ No newline at end of file
diff --git a/library/phpmailer/language/phpmailer.lang-sk.php b/library/phpmailer/language/phpmailer.lang-sk.php
new file mode 100644
index 0000000000..1722a5f526
--- /dev/null
+++ b/library/phpmailer/language/phpmailer.lang-sk.php
@@ -0,0 +1,25 @@
+<?php
+/**
+* PHPMailer language file: refer to English translation for definitive list
+* Slovak Version
+* Author: Michal Tinka <michaltinka@gmail.com>
+*/
+
+$PHPMAILER_LANG['authenticate'] = 'SMTP Error: Chyba autentifikácie.';
+$PHPMAILER_LANG['connect_host'] = 'SMTP Error: Nebolo možné nadviazať spojenie so SMTP serverom.';
+$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Error: Dáta neboli prijaté';
+$PHPMAILER_LANG['empty_message'] = 'Prázdne telo správy.';
+$PHPMAILER_LANG['encoding'] = 'Neznáme kódovanie: ';
+$PHPMAILER_LANG['execute'] = 'Nedá sa vykonať: ';
+$PHPMAILER_LANG['file_access'] = 'Súbor nebol nájdený: ';
+$PHPMAILER_LANG['file_open'] = 'File Error: Súbor sa otvoriť pre čítanie: ';
+$PHPMAILER_LANG['from_failed'] = 'Následujúca adresa From je nesprávna: ';
+$PHPMAILER_LANG['instantiate'] = 'Nedá sa vytvoriť inštancia emailovej funkcie.';
+$PHPMAILER_LANG['invalid_address'] = 'Neodoslané, emailová adresa je nesprávna: ';
+$PHPMAILER_LANG['mailer_not_supported'] = ' emailový klient nieje podporovaný.';
+$PHPMAILER_LANG['provide_address'] = 'Musíte zadať aspoň jednu emailovú adresu príjemcu.';
+$PHPMAILER_LANG['recipients_failed'] = 'SMTP Error: Adresy príjemcov niesu správne ';
+$PHPMAILER_LANG['signing'] = 'Chyba prihlasovania: ';
+$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() zlyhalo.';
+$PHPMAILER_LANG['smtp_error'] = 'SMTP chyba serveru: ';
+$PHPMAILER_LANG['variable_set'] = 'Nemožno nastaviť alebo resetovať premennú: ';
diff --git a/library/phpmailer/language/phpmailer.lang-tr.php b/library/phpmailer/language/phpmailer.lang-tr.php
index b066353f9e..abba0818d4 100644
--- a/library/phpmailer/language/phpmailer.lang-tr.php
+++ b/library/phpmailer/language/phpmailer.lang-tr.php
@@ -3,24 +3,24 @@
* PHPMailer language file: refer to English translation for definitive list
* Turkish version
* Türkçe Versiyonu
-* Tercüme Adem GENÇ - tutastes@gmail.com
+* ÝZYAZILIM - Elçin Özel - Can Yýlmaz - Mehmet Benlioðlu
*/
-$PHPMAILER_LANG['authenticate'] = 'SMTP Hatası: Kimlik doğrulanamıyor.';
-$PHPMAILER_LANG['connect_host'] = 'SMTP Hatası: SMTP hosta bağlanamıyor.';
+$PHPMAILER_LANG['authenticate'] = 'SMTP Hatası: Doğrulanamıyor.';
+$PHPMAILER_LANG['connect_host'] = 'SMTP Hatası: SMTP hosta bağlanılamıyor.';
$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Hatası: Veri kabul edilmedi.';
$PHPMAILER_LANG['empty_message'] = 'Mesaj içeriği boş';
-$PHPMAILER_LANG['encoding'] = 'Bilinmeyen kodlama: ';
-$PHPMAILER_LANG['execute'] = 'Çalıştırılamıyor: ';
+$PHPMAILER_LANG['encoding'] = 'Bilinmeyen şifreleme: ';
+$PHPMAILER_LANG['execute'] = 'Çalıtırılamıyor: ';
$PHPMAILER_LANG['file_access'] = 'Dosyaya erişilemiyor: ';
-$PHPMAILER_LANG['file_open'] = 'Dosya Hatası: Dosya açılamadı: ';
-$PHPMAILER_LANG['from_failed'] = 'Aşağıdaki adresler başarısız oldu: ';
-$PHPMAILER_LANG['instantiate'] = 'Email fonksiyonu kanıt sunulamadı.';
-$PHPMAILER_LANG['invalid_email'] = 'Geçersiz email adresi';
-$PHPMAILER_LANG['provide_address'] = 'En az bir alıcı email adresini vermeniz gerekmektedir.';
+$PHPMAILER_LANG['file_open'] = 'Dosya Hatası: Dosya açılamıyor: ';
+$PHPMAILER_LANG['from_failed'] = 'Başarısız olan gönderici adresi: ';
+$PHPMAILER_LANG['instantiate'] = 'Örnek mail fonksiyonu oluşturulamadı.';
+$PHPMAILER_LANG['invalid_address'] = 'Gönderilmedi, email adresi geçersiz: ';
+$PHPMAILER_LANG['provide_address'] = 'En az bir tane mail adresi belirtmek zorundasınız alıcının email adresi.';
$PHPMAILER_LANG['mailer_not_supported'] = ' mailler desteklenmemektedir.';
-$PHPMAILER_LANG['recipients_failed'] = 'SMTP Hatası: Aşağıdaki alıcılara teslim edilemedi: ';
-$PHPMAILER_LANG['signing'] = 'Hata İmzalama: ';
+$PHPMAILER_LANG['recipients_failed'] = 'SMTP Hatası: alıcılara ulaımadı: ';
+$PHPMAILER_LANG['signing'] = 'İmzalama hatası: ';
+$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP bağlantı() başarısız.';
$PHPMAILER_LANG['smtp_error'] = 'SMTP sunucu hatası: ';
-$PHPMAILER_LANG['variable_set'] = 'Ayarlayamıyor veya değişken sıfırlanamıyor: ';
-?> \ No newline at end of file
+$PHPMAILER_LANG['variable_set'] = 'Ayarlanamıyor yada sıfırlanamıyor: ';
diff --git a/library/phpmailer/language/phpmailer.lang-uk.php b/library/phpmailer/language/phpmailer.lang-uk.php
new file mode 100644
index 0000000000..112bba8468
--- /dev/null
+++ b/library/phpmailer/language/phpmailer.lang-uk.php
@@ -0,0 +1,24 @@
+<?php
+/**
+* PHPMailer language file: refer to English translation for definitive list
+* Ukrainian Version by Yuriy Rudyy <yrudyy@prs.net.ua>
+*/
+
+$PHPMAILER_LANG['authenticate'] = 'Помилка SMTP: помилка авторизації.';
+$PHPMAILER_LANG['connect_host'] = 'Помилка SMTP: не вдається підєднатися до серверу SMTP.';
+$PHPMAILER_LANG['data_not_accepted'] = 'Помилка SMTP: дані не прийняті.';
+$PHPMAILER_LANG['encoding'] = 'Невідомий тип кодування: ';
+$PHPMAILER_LANG['execute'] = 'Неможливо виконати команду: ';
+$PHPMAILER_LANG['file_access'] = 'Немає доступу до файлу: ';
+$PHPMAILER_LANG['file_open'] = 'Помилка файлової системи: не вдається відкрити файл: ';
+$PHPMAILER_LANG['from_failed'] = 'Невірна адреса відправника: ';
+$PHPMAILER_LANG['instantiate'] = 'Неможливо запустити функцію mail.';
+$PHPMAILER_LANG['provide_address'] = 'Будь-ласка, введіть хоча б одну адресу e-mail отримувача.';
+$PHPMAILER_LANG['mailer_not_supported'] = ' - поштовий сервер не підтримується.';
+$PHPMAILER_LANG['recipients_failed'] = 'Помилка SMTP: відправти наступним отрмувачам не вдалася: ';
+$PHPMAILER_LANG['empty_message'] = 'Пусте тіло повідомлення';
+$PHPMAILER_LANG['invalid_address'] = 'Не відправлено, невірний формат email адреси: ';
+$PHPMAILER_LANG['signing'] = 'Помилка підпису: ';
+$PHPMAILER_LANG['smtp_connect_failed'] = 'Помилка зєднання із SMTP-сервером';
+$PHPMAILER_LANG['smtp_error'] = 'Помилка SMTP-сервера: ';
+$PHPMAILER_LANG['variable_set'] = 'Неможливо встановити або перевстановити змінну: ';
diff --git a/library/phpmailer/language/phpmailer.lang-zh.php b/library/phpmailer/language/phpmailer.lang-zh.php
index fef66f8cb1..b0e8f4e091 100644
--- a/library/phpmailer/language/phpmailer.lang-zh.php
+++ b/library/phpmailer/language/phpmailer.lang-zh.php
@@ -15,7 +15,7 @@ $PHPMAILER_LANG['file_open'] = '文件錯誤:無法打開文件:';
$PHPMAILER_LANG['from_failed'] = '發送地址錯誤:';
$PHPMAILER_LANG['execute'] = '無法執行:';
$PHPMAILER_LANG['instantiate'] = '未知函數調用。';
-//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: ';
+//$PHPMAILER_LANG['invalid_address'] = 'Not sending, email address is invalid: ';
$PHPMAILER_LANG['provide_address'] = '必須提供至少一個收件人地址。';
$PHPMAILER_LANG['mailer_not_supported'] = '發信客戶端不被支持。';
$PHPMAILER_LANG['recipients_failed'] = 'SMTP 錯誤:收件人地址錯誤:';
@@ -23,4 +23,3 @@ $PHPMAILER_LANG['recipients_failed'] = 'SMTP 錯誤:收件人地址錯誤:';
//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.';
//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: ';
//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: ';
-?> \ No newline at end of file
diff --git a/library/phpmailer/language/phpmailer.lang-zh_cn.php b/library/phpmailer/language/phpmailer.lang-zh_cn.php
index b188404359..78eb9acf36 100644
--- a/library/phpmailer/language/phpmailer.lang-zh_cn.php
+++ b/library/phpmailer/language/phpmailer.lang-zh_cn.php
@@ -15,7 +15,7 @@ $PHPMAILER_LANG['file_access'] = '无法访问文件:';
$PHPMAILER_LANG['file_open'] = '文件错误:无法打开文件:';
$PHPMAILER_LANG['from_failed'] = '发送地址错误:';
$PHPMAILER_LANG['instantiate'] = '未知函数调用。';
-//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: ';
+//$PHPMAILER_LANG['invalid_address'] = 'Not sending, email address is invalid: ';
$PHPMAILER_LANG['mailer_not_supported'] = '发信客户端不被支持。';
$PHPMAILER_LANG['provide_address'] = '必须提供至少一个收件人地址。';
$PHPMAILER_LANG['recipients_failed'] = 'SMTP 错误:收件人地址错误:';
@@ -23,4 +23,3 @@ $PHPMAILER_LANG['recipients_failed'] = 'SMTP 错误:收件人地址错误:';
//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.';
//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: ';
//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: ';
-?> \ No newline at end of file