From c79fe509a79f39a2453d0e7f60a2db52195b60fe Mon Sep 17 00:00:00 2001 From: Edward Gilbert Date: Fri, 16 Jun 2023 11:08:57 -0700 Subject: [PATCH] Hotfix 2023 06 03 (#508) * Occurrence Upload adjustment - Trim off delimiters that are left on the beginning or end of filter string to ensure that null values are not included * Collection Listing bug fix - Collection categories failing to be persist * Occurrence Image Submissions issue resolution - Set default image sort order to 40 for observations to ensure that preserved specimen images do not take precedence * Image Processing bug - collection identifier (collid) failed to be passed to statistics update function * Resolve Taxonomy Harvester issues - Improve TROPICOS method of matching on infraspecific taxa - Improve close match suggestions --- classes/ImageProcessor.php | 6 +-- classes/OccurrenceEditorImages.php | 1 + classes/OccurrenceSearchSupport.php | 4 +- classes/SpecUploadBase.php | 2 +- classes/TaxonomyHarvester.php | 84 ++++++++++++++++++----------- config/symbbase.php | 2 +- 6 files changed, 61 insertions(+), 38 deletions(-) diff --git a/classes/ImageProcessor.php b/classes/ImageProcessor.php index 0b13aaba43..63d2facd95 100644 --- a/classes/ImageProcessor.php +++ b/classes/ImageProcessor.php @@ -347,8 +347,7 @@ public function loadFileData($postArr){ $occurMain = new OccurrenceMaintenance($this->conn); $this->logOrEcho('Updating statistics...'); - $occurMain->setCollidStr($this->collid); - if(!$occurMain->updateCollectionStatsBasic()){ + if(!$occurMain->updateCollectionStatsBasic($this->collid)){ $errorArr = $occurMain->getErrorArr(); foreach($errorArr as $errorStr){ $this->logOrEcho($errorStr,1); @@ -561,8 +560,7 @@ private function cleanHouse($collList){ if($collList){ $this->logOrEcho('Updating collection statistics...',2); foreach($collList as $collid){ - $occurMain->setCollidStr($collid); - if(!$occurMain->updateCollectionStatsBasic()){ + if(!$occurMain->updateCollectionStatsBasic($collid)){ $errorArr = $occurMain->getErrorArr(); foreach($errorArr as $errorStr){ $this->logOrEcho($errorStr,1); diff --git a/classes/OccurrenceEditorImages.php b/classes/OccurrenceEditorImages.php index e687b50f4d..3de944bee4 100644 --- a/classes/OccurrenceEditorImages.php +++ b/classes/OccurrenceEditorImages.php @@ -401,6 +401,7 @@ public function addImage($postArr){ if(array_key_exists('copyright',$postArr)) $imgManager->setCopyright($postArr['copyright']); if(array_key_exists('notes',$postArr)) $imgManager->setNotes($postArr['notes']); if(array_key_exists('sortoccurrence',$postArr)) $imgManager->setSortOccurrence($postArr['sortoccurrence']); + if(strpos($this->collMap['colltype'], 'Observations') !== false) $imgManager->setSortSeq(40); $sourceImgUri = $postArr['imgurl']; if($sourceImgUri){ diff --git a/classes/OccurrenceSearchSupport.php b/classes/OccurrenceSearchSupport.php index 69e9fb2c75..ffa7c88eb8 100644 --- a/classes/OccurrenceSearchSupport.php +++ b/classes/OccurrenceSearchSupport.php @@ -132,7 +132,9 @@ public function outputFullCollArr($collGrpArr, $targetCatID = '', $displayIcons
'; ?>
diff --git a/classes/SpecUploadBase.php b/classes/SpecUploadBase.php index 7ff14c2d8d..fb23acd699 100644 --- a/classes/SpecUploadBase.php +++ b/classes/SpecUploadBase.php @@ -1961,7 +1961,7 @@ protected function setUploadTargetPath(){ public function addFilterCondition($columnName, $condition, $value){ if($columnName && ($value || $condition == 'ISNULL' || $condition == 'NOTNULL')){ - $this->filterArr[strtolower($columnName)][$condition][] = strtolower(trim($value)); + $this->filterArr[strtolower($columnName)][$condition][] = strtolower(trim($value,'; ')); } } diff --git a/classes/TaxonomyHarvester.php b/classes/TaxonomyHarvester.php index 296b6073a3..65b50c8761 100644 --- a/classes/TaxonomyHarvester.php +++ b/classes/TaxonomyHarvester.php @@ -785,7 +785,7 @@ private function addTropicosTaxon($taxonArr){ $sciName = str_replace(array(' subsp.',' ssp.',' var.',' f.'), '', $sciName); $sciName = str_replace('.','', $sciName); $sciName = str_replace(' ','%20', $sciName); - $url = 'http://services.tropicos.org/Name/Search?type='.$searchType.'&format=json&name='.$sciName.'&apikey='.$this->taxonomicResources['tropicos']; + $url = 'https://services.tropicos.org/Name/Search?type='.$searchType.'&format=json&name='.$sciName.'&apikey='.$this->taxonomicResources['tropicos']; if($fh = fopen($url, 'r')){ $content = ""; while($line = fread($fh, 1024)){ @@ -794,14 +794,27 @@ private function addTropicosTaxon($taxonArr){ fclose($fh); $resultArr = json_decode($content,true); $id = 0; + $closeMatchArr = array(); foreach($resultArr as $arr){ + $unitSciname = $arr['ScientificName']; + if(strpos($unitSciname, ' fo. ')) $unitSciname = str_replace(' fo. ', ' f. ', $unitSciname); if(array_key_exists('Error', $arr)){ $this->logOrEcho('Taxon not found (code:1)',2); return; } - if(!array_key_exists('NomenclatureStatusID', $arr) || $arr['NomenclatureStatusID'] == 1){ - $id = $arr['NameId']; - break; + if($taxonArr['sciname'] != $unitSciname){ + $pattern = '/^\D+\s{1}\D+\s{1}(subsp|ssp|var|f)\.\s{1}\D+$/'; + if(preg_match($pattern, $taxonArr['sciname'])){ + if(preg_match($pattern, $unitSciname)){ + $closeMatchArr[] = $arr['NameId']; + } + } + } + else{ + if(!array_key_exists('NomenclatureStatusID', $arr) || $arr['NomenclatureStatusID'] == 1){ + $id = $arr['NameId']; + break; + } } } if($id){ @@ -810,6 +823,11 @@ private function addTropicosTaxon($taxonArr){ } else{ $this->logOrEcho('Taxon not found (code:2)',2); + if($closeMatchArr){ + foreach($closeMatchArr as $closeID){ + $this->addTropicosTaxonByID($closeID); + } + } } } else{ @@ -820,7 +838,7 @@ private function addTropicosTaxon($taxonArr){ private function addTropicosTaxonByID($id){ $taxonArr= Array(); - $url = 'http://services.tropicos.org/Name/'.$id.'?apikey='.$this->taxonomicResources['tropicos'].'&format=json'; + $url = 'https://services.tropicos.org/Name/'.$id.'?apikey='.$this->taxonomicResources['tropicos'].'&format=json'; if($fh = fopen($url, 'r')){ $content = ""; while($line = fread($fh, 1024)){ @@ -835,7 +853,7 @@ private function addTropicosTaxonByID($id){ $taxonArr['parent']['tid'] = 'self'; } else{ - $url = 'http://services.tropicos.org/Name/'.$id.'/HigherTaxa?apikey='.$this->taxonomicResources['tropicos'].'&format=json'; + $url = 'https://services.tropicos.org/Name/'.$id.'/HigherTaxa?apikey='.$this->taxonomicResources['tropicos'].'&format=json'; if($fh = fopen($url, 'r')){ $content = ''; while($line = fread($fh, 1024)){ @@ -859,7 +877,7 @@ private function addTropicosTaxonByID($id){ //Get accepted name $acceptedTid = 0; if($taxonArr['acceptedNameCount'] > 0 && $taxonArr['synonymCount'] == 0){ - $url = 'http://services.tropicos.org/Name/'.$id.'/AcceptedNames?apikey='.$this->taxonomicResources['tropicos'].'&format=json'; + $url = 'https://services.tropicos.org/Name/'.$id.'/AcceptedNames?apikey='.$this->taxonomicResources['tropicos'].'&format=json'; if($fh = fopen($url, 'r')){ $content = ''; while($line = fread($fh, 1024)){ @@ -907,14 +925,18 @@ private function getTropicosNode($nodeArr){ if(isset($nodeArr['Genus'])) $taxonArr['unitname1'] = $nodeArr['Genus']; if(isset($nodeArr['SpeciesEpithet'])) $taxonArr['unitname2'] = $nodeArr['SpeciesEpithet']; if(isset($nodeArr['source'])) $taxonArr['source'] = $nodeArr['source']; - if(!isset($taxonArr['unitname1']) && !strpos($taxonArr['sciname'],' ')) $taxonArr['unitname1'] = $taxonArr['sciname']; + if(!isset($taxonArr['unitname1']) && $taxonArr['sciname'] && !strpos($taxonArr['sciname'],' ')) $taxonArr['unitname1'] = $taxonArr['sciname']; $taxonArr['rankid'] = $this->getRankIdByTaxonArr($taxonArr); if(isset($taxonArr['unitname2']) && isset($nodeArr['OtherEpithet'])){ $taxonArr['unitname3'] = $nodeArr['OtherEpithet']; if($this->kingdomName != 'Animalia'){ if($taxonArr['rankid'] == 230) $taxonArr['unitind3'] = 'subsp.'; elseif($taxonArr['rankid'] == 240) $taxonArr['unitind3'] = 'var.'; - elseif($taxonArr['rankid'] == 260) $taxonArr['unitind3'] = 'f.'; + elseif($taxonArr['rankid'] == 260){ + $taxonArr['unitind3'] = 'f.'; + $taxonArr['sciname'] = str_replace(' fo. ', ' f. ', $taxonArr['sciname']); + } + } } return $taxonArr; @@ -1161,7 +1183,7 @@ private function loadNewTaxon($taxonArr, $tidAccepted = 0){ $sql = 'SELECT tidaccepted FROM taxstatus WHERE (taxauthid = '.$this->taxAuthId.') AND (tid = '.$newTid.')'; $rs = $this->conn->query($sql); if($r = $rs->fetch_object()){ - //Taxon is already in this thesaurus, thus link synonyms to accepted name of this taxon + //Taxon is already in this thesaurus, thus skip loading and jsut link synonyms to accepted name of this taxon $tidAccepted = $r->tidaccepted; $loadTaxon= false; } @@ -1412,22 +1434,22 @@ public function getCloseMatch($taxonStr){ $retArr = array(); $taxonStr = $this->cleanInStr($taxonStr); if($taxonStr){ - $infraArr = array('subsp','ssp','var','f'); - $taxonStringArr = explode(' ',$taxonStr); - $unitname1 = array_shift($taxonStringArr); - if(strlen($unitname1) == 1) $unitname1 = array_shift($taxonStringArr); - $unitname2 = array_shift($taxonStringArr); - if(strlen($unitname2) == 1) $unitname2 = array_shift($taxonStringArr); - $unitname3 = array_shift($taxonStringArr); - if($taxonStringArr){ - while($val = array_shift($taxonStringArr)){ - if(in_array(str_replace('.', '', $val),$infraArr)) $unitname3 = array_shift($taxonStringArr); + $infraArr = array('subsp.','ssp.','var.','f.'); + $unitArr = explode(' ', $taxonStr); + $unitname1 = $this->cleanInStr(array_shift($unitArr)); + if(strlen($unitname1) == 1) $unitname1 = $this->cleanInStr(array_shift($unitArr)); + $unitname2 = $this->cleanInStr(array_shift($unitArr)); + if(strlen($unitname2) == 1) $unitname2 = $this->cleanInStr(array_shift($unitArr)); + $infraEpithetArr = array(); + foreach($unitArr as $str){ + if(!in_array($str, $infraArr)){ + $infraEpithetArr[] = $this->cleanInStr($str); } } - if($unitname3){ + if($infraEpithetArr){ //Look for infraspecific species with different rank indicators - $sql = 'SELECT tid, sciname FROM taxa WHERE (unitname1 = "'.$unitname1.'") AND (unitname2 = "'.$unitname2.'") AND (unitname3 = "'.$unitname3.'") '; - if($this->kingdomName) $sql .= 'AND (kingdomname = "'.$this->kingdomName.'" OR kingdomname IS NULL) '; + $sql = 'SELECT tid, sciname FROM taxa WHERE (unitname1 = "'.$unitname1.'") AND (unitname2 = "'.$unitname2.'") '; + if($this->kingdomName) $sql .= 'AND (kingdomname = "'.$this->cleanInStr($this->kingdomName).'" OR kingdomname IS NULL) '; $sql .= 'ORDER BY sciname'; $rs = $this->conn->query($sql); while($row = $rs->fetch_object()){ @@ -1435,15 +1457,14 @@ public function getCloseMatch($taxonStr){ } $rs->free(); } - if($unitname2){ if(!$retArr){ //Look for match where - $searchStr = substr($unitname1,0,4).'%'; - $searchStr .= ' '.substr($unitname2,0,4).'%'; - if(strlen($unitname3) > 2) $searchStr .= ' '.substr($unitname3,0,5).'%'; + $searchStr = substr($unitname1, 0, 4).'%'; + $searchStr .= ' '.substr($unitname2, 0, 4).'%'; + if($infraEpithetArr) $searchStr .= ' '.substr($infraEpithetArr[0], 0, 5).'%'; $sql = 'SELECT tid, sciname FROM taxa WHERE (sciname LIKE "'.$searchStr.'") '; - if($this->kingdomName) $sql .= 'AND (kingdomname = "'.$this->kingdomName.'" OR kingdomname IS NULL) '; + if($this->kingdomName) $sql .= 'AND (kingdomname = "'.$this->cleanInStr($this->kingdomName).'" OR kingdomname IS NULL) '; $sql .= 'ORDER BY sciname LIMIT 15'; $rs = $this->conn->query($sql); while($row = $rs->fetch_object()){ @@ -1457,7 +1478,7 @@ public function getCloseMatch($taxonStr){ if(!$retArr){ //Look for matches based on same edithet but different genus $sql = 'SELECT tid, sciname FROM taxa WHERE (sciname LIKE "'.substr($unitname1,0,2).'% '.$unitname2.'") '; - if($this->kingdomName) $sql .= 'AND (kingdomname = "'.$this->kingdomName.'" OR kingdomname IS NULL) '; + if($this->kingdomName) $sql .= 'AND (kingdomname = "'.$this->cleanInStr($this->kingdomName).'" OR kingdomname IS NULL) '; $sql .= 'ORDER BY sciname'; $rs = $this->conn->query($sql); while($row = $rs->fetch_object()){ @@ -1467,8 +1488,8 @@ public function getCloseMatch($taxonStr){ } } //Get soundex matches - $sql = 'SELECT tid, sciname FROM taxa WHERE SOUNDEX(sciname) = SOUNDEX("'.$taxonStr.'") '; - if($this->kingdomName) $sql .= 'AND (kingdomname = "'.$this->kingdomName.'" OR kingdomname IS NULL) '; + $sql = 'SELECT tid, sciname FROM taxa WHERE SOUNDEX(sciname) = SOUNDEX("'.$this->cleanInStr($taxonStr).'") '; + if($this->kingdomName) $sql .= 'AND (kingdomname = "'.$this->cleanInStr($this->kingdomName).'" OR kingdomname IS NULL) '; $sql .= 'ORDER BY sciname LIMIT 5'; $rs = $this->conn->query($sql); while($row = $rs->fetch_object()){ @@ -1742,6 +1763,7 @@ private function setRankIdArr(){ if(isset($this->rankIdArr['form'])){ $this->rankIdArr['f.'] = $this->rankIdArr['form']; $this->rankIdArr['fo.'] = $this->rankIdArr['form']; + $this->rankIdArr['forma'] = $this->rankIdArr['form']; } } } diff --git a/config/symbbase.php b/config/symbbase.php index 1e21d05103..41c69f51aa 100644 --- a/config/symbbase.php +++ b/config/symbbase.php @@ -2,7 +2,7 @@ header('X-Frame-Options: DENY'); header('Cache-control: private'); // IE 6 FIX date_default_timezone_set('America/Phoenix'); -$CODE_VERSION = '3.0.8'; +$CODE_VERSION = '3.0.9'; if(!isset($CLIENT_ROOT) && isset($clientRoot)) $CLIENT_ROOT = $clientRoot; if(substr($CLIENT_ROOT,-1) == '/') $CLIENT_ROOT = substr($CLIENT_ROOT,0,strlen($CLIENT_ROOT)-1);