diff --git a/CHANGELOG b/CHANGELOG
index dd49c400c..12848d04a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,22 @@
+--------------------------------------------------------------------------------
+ Changes in version 5.1.27
+--------------------------------------------------------------------------------
+- fix adding new attribute definition if object type is 'all'
+- EmptyFolder runs callbacks to remove objects from index and remove preview images
+- skip internal conversion service for images if imagick extension is missing
+- running the controller will always call the hooks preRun and postRun
+- add tabs on ViewFolder page
+- link behind logo in header can be set in extension
+- move attributes for documents and folders on search page into own accordion
+- search page uses conversion mgr for preview images
+- backport export of search result from seeddms 6.0.x
+- ldap authentication used 'uid' instead 'cn' in distinguished name if
+ the initial bind failed and a second bind with the user's credentials
+ is done
+- fix sorting in search result
+- import of users can handle hidden and disabled flag
+- image conversion falls back to gd library if imagick extension is not loaded
+
--------------------------------------------------------------------------------
Changes in version 5.1.26
--------------------------------------------------------------------------------
diff --git a/SeedDMS_Core/Core/inc.ClassDMS.php b/SeedDMS_Core/Core/inc.ClassDMS.php
index ad59145d3..bfda37984 100644
--- a/SeedDMS_Core/Core/inc.ClassDMS.php
+++ b/SeedDMS_Core/Core/inc.ClassDMS.php
@@ -387,7 +387,7 @@ class SeedDMS_Core_DMS {
$this->lasterror = '';
$this->version = '@package_version@';
if($this->version[0] == '@')
- $this->version = '5.1.26';
+ $this->version = '5.1.27';
} /* }}} */
/**
@@ -1542,8 +1542,8 @@ class SeedDMS_Core_DMS {
if(is_string($attribute))
$attribute = array($attribute);
$searchAttributes[] = "EXISTS (SELECT NULL FROM `tblFolderAttributes` WHERE `tblFolderAttributes`.`attrdef`=".$attrdefid." AND (`tblFolderAttributes`.`value` like '%".$valueset[0].implode("%' OR `tblFolderAttributes`.`value` like '%".$valueset[0], $attribute)."%') AND `tblFolderAttributes`.`folder`=`tblFolders`.`id`)";
- } elseif(is_string($attribute)) {
- $searchAttributes[] = "EXISTS (SELECT NULL FROM `tblFolderAttributes` WHERE `tblFolderAttributes`.`attrdef`=".$attrdefid." AND `tblFolderAttributes`.`value`='".$attribute."' AND `tblFolderAttributes`.`folder`=`tblFolders`.`id`)";
+ } else {
+ $searchAttributes[] = "EXISTS (SELECT NULL FROM `tblFolderAttributes` WHERE `tblFolderAttributes`.`attrdef`=".$attrdefid." AND (`tblFolderAttributes`.`value`='".(is_array($attribute) ? implode("' OR `tblFolderAttributes`.`value` = '", $attribute) : $attribute)."') AND `tblFolderAttributes`.`folder`=`tblFolders`.`id`)";
}
} else {
if($attrdef->getType() == SeedDMS_Core_AttributeDefinition::type_date && is_array($attribute)) {
@@ -1630,12 +1630,14 @@ class SeedDMS_Core_DMS {
$searchQuery .= " ORDER BY `tblFolders`.`name` DESC";
break;
case 'na':
+ case 'n':
$searchQuery .= " ORDER BY `tblFolders`.`name`";
break;
case 'id':
$searchQuery .= " ORDER BY `tblFolders`.`id` DESC";
break;
case 'ia':
+ case 'i':
$searchQuery .= " ORDER BY `tblFolders`.`id`";
break;
default:
@@ -1739,7 +1741,7 @@ class SeedDMS_Core_DMS {
$attribute = array($attribute);
$lsearchAttributes[] = "EXISTS (SELECT NULL FROM `tblDocumentAttributes` WHERE `tblDocumentAttributes`.`attrdef`=".$attrdefid." AND (`tblDocumentAttributes`.`value` like '%".$valueset[0].implode("%' OR `tblDocumentAttributes`.`value` like '%".$valueset[0], $attribute)."%') AND `tblDocumentAttributes`.`document` = `tblDocuments`.`id`)";
} else
- $lsearchAttributes[] = "EXISTS (SELECT NULL FROM `tblDocumentAttributes` WHERE `tblDocumentAttributes`.`attrdef`=".$attrdefid." AND `tblDocumentAttributes`.`value`='".$attribute."' AND `tblDocumentAttributes`.`document` = `tblDocuments`.`id`)";
+ $lsearchAttributes[] = "EXISTS (SELECT NULL FROM `tblDocumentAttributes` WHERE `tblDocumentAttributes`.`attrdef`=".$attrdefid." AND (`tblDocumentAttributes`.`value`='".(is_array($attribute) ? implode("' OR `tblDocumentAttributes`.`value` = '", $attribute) : $attribute)."') AND `tblDocumentAttributes`.`document` = `tblDocuments`.`id`)";
} else {
if($attrdef->getType() == SeedDMS_Core_AttributeDefinition::type_date && is_array($attribute)) {
$kkll = [];
@@ -1762,7 +1764,7 @@ class SeedDMS_Core_DMS {
$attribute = array($attribute);
$lsearchAttributes[] = "EXISTS (SELECT NULL FROM `tblDocumentContentAttributes` WHERE `tblDocumentContentAttributes`.`attrdef`=".$attrdefid." AND (`tblDocumentContentAttributes`.`value` like '%".$valueset[0].implode("%' OR `tblDocumentContentAttributes`.`value` like '%".$valueset[0], $attribute)."%') AND `tblDocumentContentAttributes`.`content` = `tblDocumentContent`.`id`)";
} else {
- $lsearchAttributes[] = "EXISTS (SELECT NULL FROM `tblDocumentContentAttributes` WHERE `tblDocumentContentAttributes`.`attrdef`=".$attrdefid." AND `tblDocumentContentAttributes`.`value`='".$attribute."' AND `tblDocumentContentAttributes`.content = `tblDocumentContent`.id)";
+ $lsearchAttributes[] = "EXISTS (SELECT NULL FROM `tblDocumentContentAttributes` WHERE `tblDocumentContentAttributes`.`attrdef`=".$attrdefid." AND (`tblDocumentContentAttributes`.`value`='".(is_array($attribute) ? implode("' OR `tblDocumentContentAttributes`.`value` = '", $attribute) : $attribute)."') AND `tblDocumentContentAttributes`.content = `tblDocumentContent`.id)";
}
} else {
if($attrdef->getType() == SeedDMS_Core_AttributeDefinition::type_date && is_array($attribute)) {
@@ -1934,12 +1936,14 @@ class SeedDMS_Core_DMS {
$orderbyQuery = " ORDER BY `tblDocuments`.`name` DESC";
break;
case 'na':
+ case 'n':
$orderbyQuery = " ORDER BY `tblDocuments`.`name`";
break;
case 'id':
$orderbyQuery = " ORDER BY `tblDocuments`.`id` DESC";
break;
case 'ia':
+ case 'i':
$orderbyQuery = " ORDER BY `tblDocuments`.`id`";
break;
default:
@@ -2703,7 +2707,7 @@ class SeedDMS_Core_DMS {
if (is_object($this->getAttributeDefinitionByName($name))) {
return false;
}
- if(!$objtype)
+ if($objtype < SeedDMS_Core_AttributeDefinition::objtype_all || $objtype > SeedDMS_Core_AttributeDefinition::objtype_documentcontent)
return false;
if(!$type)
return false;
diff --git a/SeedDMS_Core/package.xml b/SeedDMS_Core/package.xml
index 1d88541ca..853ed07d6 100644
--- a/SeedDMS_Core/package.xml
+++ b/SeedDMS_Core/package.xml
@@ -12,11 +12,11 @@
uwe@steinmann.cx
yes
- 2022-04-25
+ 2022-08-31
- 5.1.26
- 5.1.26
+ 5.1.27
+ 5.1.27
stable
@@ -24,12 +24,9 @@
GPL License
-- fix validating multi value attributes
-- SeedDMS_Core_User::removeFromProcesses() can be limited to a list of documents. In that case only the last version will be modified.
-- add more types to getStatisticalData()
-- add optional parameter $op to SeedDMS_Core_AttributeDefinition::getObjects()
-- SeedDMS_Core_AttributeDefinition::getObjects() will not filter by value if null is passed
-- SeedDMS_Core_DMS::getAllAttributeDefinitions() has second parameter to filter attributes by type
+- fix SeedDMS_Core_DMS::addAttributeDefinition() when objtype is 0
+- sort search result even if sortorder is 'i' or 'n'
+- pass an array as an attribute to search() will OR each element
@@ -1974,5 +1971,26 @@ add method SeedDMS_Core_DatabaseAccess::setLogFp()
- fix searching for document content with a custom attribute having a value set
+
+ 2022-04-25
+
+
+ 5.1.26
+ 5.1.26
+
+
+ stable
+ stable
+
+ GPL License
+
+- fix validating multi value attributes
+- SeedDMS_Core_User::removeFromProcesses() can be limited to a list of documents. In that case only the last version will be modified.
+- add more types to getStatisticalData()
+- add optional parameter $op to SeedDMS_Core_AttributeDefinition::getObjects()
+- SeedDMS_Core_AttributeDefinition::getObjects() will not filter by value if null is passed
+- SeedDMS_Core_DMS::getAllAttributeDefinitions() has second parameter to filter attributes by type
+
+
diff --git a/TODO b/TODO
index 830548653..affeada6a 100644
--- a/TODO
+++ b/TODO
@@ -1,3 +1,6 @@
+This list is hopelessly outdated, but some of the issues are
+still worth to be implemented!
+
Update comment and date of a review/approval, if the same status is set
again. Currently setting the same status is turned of, because it didn't
have any effect, which is quite confusing if the user can do an operation
@@ -25,8 +28,6 @@ approaches to get the configuration directory.
Show expiration status of documents in document list
-Copy folders recursivly
-
Allow operations like delete, move, approve, etc. on a list of documents
installation script:
diff --git a/composer-dist.json b/composer-dist.json
index 43624bd3a..7c0171634 100644
--- a/composer-dist.json
+++ b/composer-dist.json
@@ -11,6 +11,7 @@
"pear/auth_sasl": "*",
"pear/db": "*",
"alecrabbit/php-console-colour": "*",
- "zf1/zend-search-lucene": "*"
+ "zf1/zend-search-lucene": "*",
+ "symfony/http-foundation": "^5.4"
}
}
diff --git a/controllers/class.AddDocument.php b/controllers/class.AddDocument.php
index d3ecb2679..bf6e9fb69 100644
--- a/controllers/class.AddDocument.php
+++ b/controllers/class.AddDocument.php
@@ -64,7 +64,7 @@ class SeedDMS_Controller_AddDocument extends SeedDMS_Controller_Common {
$attribute = date('Y-m-d', makeTsFromDate($attribute));
break;
}
- if(!$attrdef->validate($attribute)) {
+ if(!$attrdef->validate($attribute, null, true)) {
$this->errormsg = getAttributeValidationError($attrdef->getValidationError(), $attrdef->getName(), $attribute);
return false;
}
@@ -88,10 +88,13 @@ class SeedDMS_Controller_AddDocument extends SeedDMS_Controller_Common {
$attribute = date('Y-m-d', makeTsFromDate($attribute));
break;
}
- if(!$attrdef->validate($attribute)) {
+ if(!$attrdef->validate($attribute, null, true)) {
$this->errormsg = getAttributeValidationError($attrdef->getValidationError(), $attrdef->getName(), $attribute);
return false;
}
+ } elseif($attrdef->getMinValues() > 0) {
+ $this->errormsg = array("attr_min_values", array("attrname"=>$attrdef->getName()));
+ return false;
}
} else {
if($ret === false)
diff --git a/controllers/class.AddSubFolder.php b/controllers/class.AddSubFolder.php
index 9b1835a12..24a609cb8 100644
--- a/controllers/class.AddSubFolder.php
+++ b/controllers/class.AddSubFolder.php
@@ -45,7 +45,12 @@ class SeedDMS_Controller_AddSubFolder extends SeedDMS_Controller_Common {
if($attrdef = $dms->getAttributeDefinition($attrdefid)) {
if(null === ($ret = $this->callHook('validateAttribute', $attrdef, $attribute))) {
if($attribute) {
- if(!$attrdef->validate($attribute)) {
+ switch($attrdef->getType()) {
+ case SeedDMS_Core_AttributeDefinition::type_date:
+ $attribute = date('Y-m-d', makeTsFromDate($attribute));
+ break;
+ }
+ if(!$attrdef->validate($attribute, null, true)) {
$this->errormsg = getAttributeValidationError($attrdef->getValidationError(), $attrdef->getName(), $attribute);
return false;
}
diff --git a/controllers/class.DocumentAccess.php b/controllers/class.DocumentAccess.php
index aaeb6a457..e3da3cacd 100644
--- a/controllers/class.DocumentAccess.php
+++ b/controllers/class.DocumentAccess.php
@@ -30,119 +30,180 @@ class SeedDMS_Controller_DocumentAccess extends SeedDMS_Controller_Common {
$settings = $this->params['settings'];
$action = $this->params['action'];
- // Change owner -----------------------------------------------------------
- if ($action == "setowner") {
- if(false === $this->callHook('preSetOwner', $document)) {
- if(empty($this->errormsg))
- $this->errormsg = 'hook_preSetOwner_failed';
- return null;
- }
- $newowner = $this->params['newowner'];
- $oldowner = $document->getOwner();
- if($document->setOwner($newowner)) {
- if(false === $this->callHook('postSetOwner', $document, $oldowner)) {
- if(empty($this->errormsg))
- $this->errormsg = 'hook_postSetOwner_failed';
- return null;
- }
- }
- } elseif ($action == "notinherit") {
- if(false === $this->callHook('preSetNotInherit', $document)) {
- if(empty($this->errormsg))
- $this->errormsg = 'hook_preSetNotInherit_failed';
- return null;
- }
+ return null;
+ }
- /* Get default access before access is not longer inherited. This
- * will return the default access from the parent folder.
- */
- $defAccess = $document->getDefaultAccess();
- if(!$document->setInheritAccess(false)) {
- return false;
- }
+ // Change owner -----------------------------------------------------------
+ public function setowner() {
+ $dms = $this->params['dms'];
+ $user = $this->params['user'];
+ $folder = $this->params['folder'];
+ $document = $this->params['document'];
+ $settings = $this->params['settings'];
- if(!$document->setDefaultAccess($defAccess)) {
- return false;
- }
-
- //copy ACL of parent folder
- $mode = $this->params['mode'];
- if ($mode == "copy") {
- $accessList = $folder->getAccessList();
- foreach ($accessList["users"] as $userAccess)
- $document->addAccess($userAccess->getMode(), $userAccess->getUserID(), true);
- foreach ($accessList["groups"] as $groupAccess)
- $document->addAccess($groupAccess->getMode(), $groupAccess->getGroupID(), false);
- }
-
- if(false === $this->callHook('postSetNotInherit', $document)) {
+ if(false === $this->callHook('preSetOwner', $document)) {
+ if(empty($this->errormsg))
+ $this->errormsg = 'hook_preSetOwner_failed';
+ return null;
+ }
+ $newowner = $this->params['newowner'];
+ $oldowner = $document->getOwner();
+ if($document->setOwner($newowner)) {
+ if(false === $this->callHook('postSetOwner', $document, $oldowner)) {
if(empty($this->errormsg))
- $this->errormsg = 'hook_postSetNotInherit_failed';
+ $this->errormsg = 'hook_postSetOwner_failed';
return null;
}
- } elseif ($action == "inherit") {
- if(false === $this->callHook('preSetInherit', $document)) {
- if(empty($this->errormsg))
- $this->errormsg = 'hook_preSetInherit_failed';
- return null;
- }
- if(!$document->clearAccessList() || !$document->setInheritAccess(true)) {
- return false;
- }
-
- if(false === $this->callHook('postSetInherit', $document)) {
- if(empty($this->errormsg))
- $this->errormsg = 'hook_postSetInherit_failed';
- return null;
- }
- } elseif ($action == "setdefault") {
- if(false === $this->callHook('preSetDefault', $document)) {
- if(empty($this->errormsg))
- $this->errormsg = 'hook_preSetDefault_failed';
- return null;
- }
-
- $mode = $this->params['mode'];
- if(!$document->setDefaultAccess($mode)) {
- return false;
- }
-
- if(false === $this->callHook('postSetDefault', $document)) {
- if(empty($this->errormsg))
- $this->errormsg = 'hook_postSetDefault_failed';
- return null;
- }
- } elseif ($action == "editaccess") {
- $mode = $this->params['mode'];
- $userid = $this->params['userid'];
- $groupid = $this->params['groupid'];
- if ($userid) {
- $document->changeAccess($mode, $userid, true);
- }
- elseif ($groupid) {
- $document->changeAccess($mode, $groupid, false);
- }
- } elseif ($action == "delaccess") {
- $userid = $this->params['userid'];
- $groupid = $this->params['groupid'];
- if ($userid) {
- $document->removeAccess($userid, true);
- }
- elseif ($groupid) {
- $document->removeAccess($groupid, false);
- }
- } elseif ($action == "addaccess") {
- $mode = $this->params['mode'];
- $userid = $this->params['userid'];
- $groupid = $this->params['groupid'];
- if ($userid && $userid != -1) {
- $document->addAccess($mode, $userid, true);
- }
- elseif ($groupid && $groupid != -1) {
- $document->addAccess($mode, $groupid, false);
- }
}
+ return true;
+ }
+ public function notinherit() {
+ $dms = $this->params['dms'];
+ $user = $this->params['user'];
+ $folder = $this->params['folder'];
+ $document = $this->params['document'];
+ $settings = $this->params['settings'];
+
+ if(false === $this->callHook('preSetNotInherit', $document)) {
+ if(empty($this->errormsg))
+ $this->errormsg = 'hook_preSetNotInherit_failed';
+ return null;
+ }
+
+ /* Get default access before access is not longer inherited. This
+ * will return the default access from the parent folder.
+ */
+ $defAccess = $document->getDefaultAccess();
+ if(!$document->setInheritAccess(false)) {
+ return false;
+ }
+
+ if(!$document->setDefaultAccess($defAccess)) {
+ return false;
+ }
+
+ //copy ACL of parent folder
+ $mode = $this->params['mode'];
+ if ($mode == "copy") {
+ $accessList = $folder->getAccessList();
+ foreach ($accessList["users"] as $userAccess)
+ $document->addAccess($userAccess->getMode(), $userAccess->getUserID(), true);
+ foreach ($accessList["groups"] as $groupAccess)
+ $document->addAccess($groupAccess->getMode(), $groupAccess->getGroupID(), false);
+ }
+
+ if(false === $this->callHook('postSetNotInherit', $document)) {
+ if(empty($this->errormsg))
+ $this->errormsg = 'hook_postSetNotInherit_failed';
+ return null;
+ }
+ return true;
+ }
+
+ public function inherit() {
+ $dms = $this->params['dms'];
+ $user = $this->params['user'];
+ $folder = $this->params['folder'];
+ $document = $this->params['document'];
+ $settings = $this->params['settings'];
+
+ if(false === $this->callHook('preSetInherit', $document)) {
+ if(empty($this->errormsg))
+ $this->errormsg = 'hook_preSetInherit_failed';
+ return null;
+ }
+ if(!$document->clearAccessList() || !$document->setInheritAccess(true)) {
+ return false;
+ }
+
+ if(false === $this->callHook('postSetInherit', $document)) {
+ if(empty($this->errormsg))
+ $this->errormsg = 'hook_postSetInherit_failed';
+ return null;
+ }
+ return true;
+ }
+
+ public function setdefault() {
+ $dms = $this->params['dms'];
+ $user = $this->params['user'];
+ $folder = $this->params['folder'];
+ $document = $this->params['document'];
+ $settings = $this->params['settings'];
+
+ if(false === $this->callHook('preSetDefault', $document)) {
+ if(empty($this->errormsg))
+ $this->errormsg = 'hook_preSetDefault_failed';
+ return null;
+ }
+
+ $mode = $this->params['mode'];
+ if(!$document->setDefaultAccess($mode)) {
+ return false;
+ }
+
+ if(false === $this->callHook('postSetDefault', $document)) {
+ if(empty($this->errormsg))
+ $this->errormsg = 'hook_postSetDefault_failed';
+ return null;
+ }
+ return true;
+ }
+
+ public function editaccess() {
+ $dms = $this->params['dms'];
+ $user = $this->params['user'];
+ $folder = $this->params['folder'];
+ $document = $this->params['document'];
+ $settings = $this->params['settings'];
+
+ $mode = $this->params['mode'];
+ $userid = $this->params['userid'];
+ $groupid = $this->params['groupid'];
+ if ($userid) {
+ $document->changeAccess($mode, $userid, true);
+ }
+ elseif ($groupid) {
+ $document->changeAccess($mode, $groupid, false);
+ }
+ return true;
+ }
+
+ public function delaccess() {
+ $dms = $this->params['dms'];
+ $user = $this->params['user'];
+ $folder = $this->params['folder'];
+ $document = $this->params['document'];
+ $settings = $this->params['settings'];
+
+ $userid = $this->params['userid'];
+ $groupid = $this->params['groupid'];
+ if ($userid) {
+ $document->removeAccess($userid, true);
+ }
+ elseif ($groupid) {
+ $document->removeAccess($groupid, false);
+ }
+ return true;
+ }
+
+ public function addaccess() {
+ $dms = $this->params['dms'];
+ $user = $this->params['user'];
+ $folder = $this->params['folder'];
+ $document = $this->params['document'];
+ $settings = $this->params['settings'];
+
+ $mode = $this->params['mode'];
+ $userid = $this->params['userid'];
+ $groupid = $this->params['groupid'];
+ if ($userid && $userid != -1) {
+ $document->addAccess($mode, $userid, true);
+ }
+ elseif ($groupid && $groupid != -1) {
+ $document->addAccess($mode, $groupid, false);
+ }
return true;
}
}
diff --git a/controllers/class.EditDocument.php b/controllers/class.EditDocument.php
index 483972780..a67011a65 100644
--- a/controllers/class.EditDocument.php
+++ b/controllers/class.EditDocument.php
@@ -125,7 +125,7 @@ class SeedDMS_Controller_EditDocument extends SeedDMS_Controller_Common {
$attribute = date('Y-m-d', makeTsFromDate($attribute));
break;
}
- if(!$attrdef->validate($attribute, $document, true)) {
+ if(!$attrdef->validate($attribute, $document, false)) {
$this->errormsg = getAttributeValidationError($attrdef->getValidationError(), $attrdef->getName(), $attribute);
return false;
}
diff --git a/controllers/class.EditFolder.php b/controllers/class.EditFolder.php
index 9f8aee5aa..818f146b2 100644
--- a/controllers/class.EditFolder.php
+++ b/controllers/class.EditFolder.php
@@ -59,7 +59,7 @@ class SeedDMS_Controller_EditFolder extends SeedDMS_Controller_Common {
$attribute = date('Y-m-d', makeTsFromDate($attribute));
break;
}
- if(!$attrdef->validate($attribute, $folder, true)) {
+ if(!$attrdef->validate($attribute, $folder, false)) {
$this->errormsg = getAttributeValidationText($attrdef->getValidationError(), $attrdef->getName(), $attribute);
return false;
}
@@ -70,6 +70,7 @@ class SeedDMS_Controller_EditFolder extends SeedDMS_Controller_Common {
}
} elseif($attrdef->getMinValues() > 0) {
$this->errormsg = getMLText("attr_min_values", array("attrname"=>$attrdef->getName()));
+ return false;
} elseif(isset($oldattributes[$attrdefid])) {
if(!$folder->removeAttribute($dms->getAttributeDefinition($attrdefid)))
return false;
diff --git a/controllers/class.EmptyFolder.php b/controllers/class.EmptyFolder.php
index a6629923c..eb1c5a629 100644
--- a/controllers/class.EmptyFolder.php
+++ b/controllers/class.EmptyFolder.php
@@ -22,41 +22,64 @@
*/
class SeedDMS_Controller_EmptyFolder extends SeedDMS_Controller_Common {
- public function run() {
+ /* Register a callback which removes each document/folder from the fulltext index
+ * The callback must return null otherwise the removal will be canceled.
+ */
+ static function removeFromIndex($arr, $object) { /* {{{ */
+ $fulltextservice = $arr[0];
+ $lucenesearch = $fulltextservice->Search();
+ $hit = null;
+ if($object->isType('document'))
+ $hit = $lucenesearch->getDocument($object->getID());
+ elseif($object->isType('folder'))
+ $hit = $lucenesearch->getFolder($object->getID());
+ if($hit) {
+ $index = $fulltextservice->Indexer();
+ $index->delete($hit->id);
+ $index->commit();
+ }
+ return null;
+ } /* }}} */
+
+ static function removePreviews($arr, $document) { /* {{{ */
+ $previewer = $arr[0];
+
+ $previewer->deleteDocumentPreviews($document);
+ return null;
+ } /* }}} */
+
+ public function run() { /* {{{ */
$dms = $this->params['dms'];
$user = $this->params['user'];
$settings = $this->params['settings'];
$folder = $this->params['folder'];
- $index = $this->params['index'];
- $indexconf = $this->params['indexconf'];
+ $fulltextservice = $this->params['fulltextservice'];
- /* Get the document id and name before removing the document */
+ /* Get the folder id and name before removing the folder */
$foldername = $folder->getName();
$folderid = $folder->getID();
if(false === $this->callHook('preEmptyFolder')) {
if(empty($this->errormsg))
$this->errormsg = 'hook_preEmptyFolder_failed';
- return null;
+ return false;
}
$result = $this->callHook('emptyFolder', $folder);
if($result === null) {
- /* Register a callback which removes each document from the fulltext index
- * The callback must return null other the removal will be canceled.
- */
- function removeFromIndex($arr, $document) {
- $index = $arr[0];
- $indexconf = $arr[1];
- $lucenesearch = new $indexconf['Search']($index);
- if($hit = $lucenesearch->getDocument($document->getID())) {
- $index->delete($hit->id);
- $index->commit();
- }
- return null;
+ if($fulltextservice && ($index = $fulltextservice->Indexer())) {
+ /* Register a callback which is called by SeedDMS_Core when a folder
+ * or document is removed. The second parameter passed to this callback
+ * is the document or folder to be removed.
+ */
+ $dms->addCallback('onPreRemoveDocument', 'SeedDMS_Controller_EmptyFolder::removeFromIndex', array($fulltextservice));
+ $dms->addCallback('onPreRemoveFolder', 'SeedDMS_Controller_EmptyFolder::removeFromIndex', array($fulltextservice));
}
- if($index)
- $dms->setCallback('onPreEmptyDocument', 'removeFromIndex', array($index, $indexconf));
+
+ /* Register another callback which removes the preview images of the document */
+ require_once("SeedDMS/Preview.php");
+ $previewer = new SeedDMS_Preview_Previewer($settings->_cacheDir);
+ $dms->addCallback('onPreRemoveDocument', 'SeedDMS_Controller_EmptyFolder::removePreviews', array($previewer));
if (!$folder->emptyFolder()) {
$this->errormsg = 'error_occured';
@@ -72,5 +95,5 @@ class SeedDMS_Controller_EmptyFolder extends SeedDMS_Controller_Common {
}
return true;
- }
+ } /* }}} */
}
diff --git a/controllers/class.Preview.php b/controllers/class.Preview.php
index 3cea95428..af8075dd1 100644
--- a/controllers/class.Preview.php
+++ b/controllers/class.Preview.php
@@ -22,96 +22,93 @@
*/
class SeedDMS_Controller_Preview extends SeedDMS_Controller_Common {
- public function run() {
- global $theme;
+ public function version() { /* {{{ */
$dms = $this->params['dms'];
- $type = $this->params['type'];
$settings = $this->params['settings'];
$conversionmgr = $this->params['conversionmgr'];
- switch($type) {
- case "version":
- $version = $this->params['version'];
- $document = $this->params['document'];
- $width = $this->params['width'];
- if($version < 1) {
- $content = $this->callHook('documentLatestContent', $document);
- if($content === null)
- $content = $document->getLatestContent();
- } else {
- $content = $this->callHook('documentContent', $document, $version);
- if($content === null)
- $content = $document->getContentByVersion($version);
- }
- if (!is_object($content)) {
- $this->errormsg = 'invalid_version';
- return false;
- }
- /* set params['content'] for compatiblity with older extensions which
- * expect the content in the controller
- */
- $this->params['content'] = $content;
- if(null === $this->callHook('version')) {
- if($width)
- $previewer = new SeedDMS_Preview_Previewer($settings->_cacheDir, $width, $settings->_cmdTimeout);
- else
- $previewer = new SeedDMS_Preview_Previewer($settings->_cacheDir);
- if($conversionmgr)
- $previewer->setConversionMgr($conversionmgr);
- else
- $previewer->setConverters($settings->_converters['preview']);
- $previewer->setXsendfile($settings->_enableXsendfile);
- if(!$previewer->hasPreview($content)) {
- add_log_line("");
- if(!$previewer->createPreview($content)) {
- add_log_line("", PEAR_LOG_ERR);
- }
- }
- if(!$previewer->hasPreview($content)) {
- header('Content-Type: image/svg+xml');
- readfile('../views/'.$theme.'/images/empty.svg');
- exit;
- }
- header('Content-Type: image/png');
- $previewer->getPreview($content);
- }
- break;
- case "file":
- $object = $this->params['object'];
- $document = $this->params['document'];
- $width = $this->params['width'];
- if (!is_object($object)) {
- $this->errormsg = 'invalid_version';
- return false;
- }
-
- if(null === $this->callHook('file')) {
- if($width)
- $previewer = new SeedDMS_Preview_Previewer($settings->_cacheDir, $width, $settings->_cmdTimeout);
- else
- $previewer = new SeedDMS_Preview_Previewer($settings->_cacheDir);
- if($conversionmgr)
- $previewer->setConversionMgr($conversionmgr);
- else
- $previewer->setConverters($settings->_converters['preview']);
- $previewer->setXsendfile($settings->_enableXsendfile);
-
- if(!$previewer->hasPreview($object)) {
- add_log_line("");
- if(!$previewer->createPreview($object)) {
- add_log_line("", PEAR_LOG_ERR);
- }
- }
- if(!$previewer->hasPreview($object)) {
- header('Content-Type: image/svg+xml');
- readfile('../views/'.$theme.'/images/empty.svg');
- exit;
- }
- header('Content-Type: image/png');
- $previewer->getPreview($object);
- }
- break;
+ $version = $this->params['version'];
+ $document = $this->params['document'];
+ $width = $this->params['width'];
+ if($version < 1) {
+ $content = $this->callHook('documentLatestContent', $document);
+ if($content === null)
+ $content = $document->getLatestContent();
+ } else {
+ $content = $this->callHook('documentContent', $document, $version);
+ if($content === null)
+ $content = $document->getContentByVersion($version);
}
- return true;
- }
+ if (!is_object($content)) {
+ $this->errormsg = 'invalid_version';
+ return false;
+ }
+ /* set params['content'] for compatiblity with older extensions which
+ * expect the content in the controller
+ */
+ $this->params['content'] = $content;
+ if(null === $this->callHook('version')) {
+ if($width)
+ $previewer = new SeedDMS_Preview_Previewer($settings->_cacheDir, $width, $settings->_cmdTimeout);
+ else
+ $previewer = new SeedDMS_Preview_Previewer($settings->_cacheDir);
+ if($conversionmgr)
+ $previewer->setConversionMgr($conversionmgr);
+ else
+ $previewer->setConverters($settings->_converters['preview']);
+ $previewer->setXsendfile($settings->_enableXsendfile);
+ if(!$previewer->hasPreview($content)) {
+ add_log_line("");
+ if(!$previewer->createPreview($content)) {
+ add_log_line("", PEAR_LOG_ERR);
+ }
+ }
+ if(!$previewer->hasPreview($content)) {
+ return false;
+ }
+ header('Content-Type: image/png');
+ $previewer->getPreview($content);
+ return true;
+ }
+ } /* }}} */
+
+ public function file() { /* {{{ */
+ $dms = $this->params['dms'];
+ $settings = $this->params['settings'];
+ $conversionmgr = $this->params['conversionmgr'];
+
+ $object = $this->params['object'];
+ $document = $this->params['document'];
+ $width = $this->params['width'];
+ if (!is_object($object)) {
+ $this->errormsg = 'invalid_version';
+ return false;
+ }
+
+ if(null === $this->callHook('file')) {
+ if($width)
+ $previewer = new SeedDMS_Preview_Previewer($settings->_cacheDir, $width, $settings->_cmdTimeout);
+ else
+ $previewer = new SeedDMS_Preview_Previewer($settings->_cacheDir);
+ if($conversionmgr)
+ $previewer->setConversionMgr($conversionmgr);
+ else
+ $previewer->setConverters($settings->_converters['preview']);
+ $previewer->setXsendfile($settings->_enableXsendfile);
+
+ if(!$previewer->hasPreview($object)) {
+ add_log_line("");
+ if(!$previewer->createPreview($object)) {
+ add_log_line("", PEAR_LOG_ERR);
+ }
+ }
+ if(!$previewer->hasPreview($object)) {
+ return false;
+ }
+ header('Content-Type: image/png');
+ $previewer->getPreview($object);
+ return true;
+ }
+ } /* }}} */
+
}
diff --git a/controllers/class.RemoveFolder.php b/controllers/class.RemoveFolder.php
index a0633d093..ac64f246a 100644
--- a/controllers/class.RemoveFolder.php
+++ b/controllers/class.RemoveFolder.php
@@ -22,17 +22,17 @@
*/
class SeedDMS_Controller_RemoveFolder extends SeedDMS_Controller_Common {
- /* Register a callback which removes each document from the fulltext index
+ /* Register a callback which removes each document/folder from the fulltext index
* The callback must return null otherwise the removal will be canceled.
*/
- static function removeFromIndex($arr, $document) { /* {{{ */
+ static function removeFromIndex($arr, $object) { /* {{{ */
$fulltextservice = $arr[0];
$lucenesearch = $fulltextservice->Search();
$hit = null;
- if($document->isType('document'))
- $hit = $lucenesearch->getDocument($document->getID());
- elseif($document->isType('folder'))
- $hit = $lucenesearch->getFolder($document->getID());
+ if($object->isType('document'))
+ $hit = $lucenesearch->getDocument($object->getID());
+ elseif($object->isType('folder'))
+ $hit = $lucenesearch->getFolder($object->getID());
if($hit) {
$index = $fulltextservice->Indexer();
$index->delete($hit->id);
@@ -55,7 +55,7 @@ class SeedDMS_Controller_RemoveFolder extends SeedDMS_Controller_Common {
$folder = $this->params['folder'];
$fulltextservice = $this->params['fulltextservice'];
- /* Get the document id and name before removing the document */
+ /* Get the folder id and name before removing the folder */
$foldername = $folder->getName();
$folderid = $folder->getID();
diff --git a/controllers/class.ViewOnline.php b/controllers/class.ViewOnline.php
index 7d071db17..6b9ca3f0a 100644
--- a/controllers/class.ViewOnline.php
+++ b/controllers/class.ViewOnline.php
@@ -49,16 +49,19 @@ class SeedDMS_Controller_ViewOnline extends SeedDMS_Controller_Common {
*/
$this->params['content'] = $content;
if(null === $this->callHook('version')) {
- header("Content-Type: " . $content->getMimeType());
- $efilename = rawurlencode($content->getOriginalFileName());
- if (!isset($settings->_viewOnlineFileTypes) || !is_array($settings->_viewOnlineFileTypes) || !in_array(strtolower($content->getFileType()), $settings->_viewOnlineFileTypes)) {
- header("Content-Disposition: attachment; filename=\"" . $efilename . "\"; filename*=UTF-8''".$efilename);
- } else {
- header("Content-Disposition: filename=\"" . $efilename . "\"; filename*=UTF-8''".$efilename);
- }
- header("Cache-Control: must-revalidate");
+ if(file_exists($dms->contentDir . $content->getPath())) {
+ header("Content-Type: " . $content->getMimeType());
+ $efilename = rawurlencode($content->getOriginalFileName());
+ if (!isset($settings->_viewOnlineFileTypes) || !is_array($settings->_viewOnlineFileTypes) || !in_array(strtolower($content->getFileType()), $settings->_viewOnlineFileTypes)) {
+ header("Content-Disposition: attachment; filename=\"" . $efilename . "\"; filename*=UTF-8''".$efilename);
+ } else {
+ header("Content-Disposition: filename=\"" . $efilename . "\"; filename*=UTF-8''".$efilename);
+ }
+ header("Cache-Control: must-revalidate");
+ header("ETag: ".$content->getChecksum());
- sendFile($dms->contentDir.$content->getPath());
+ sendFile($dms->contentDir.$content->getPath());
+ }
}
break;
}
diff --git a/doc/README.Ldap b/doc/README.Ldap
new file mode 100644
index 000000000..7940ca091
--- /dev/null
+++ b/doc/README.Ldap
@@ -0,0 +1,58 @@
+Ldap configuration
+===================
+
+The configuration for authentication against an ldap server needs to be done
+the settings.xml file using a text editor. It cannot be edited from within the
+web gui.
+
+SeedDMS supports ldap authentication using an Active Directory (AD) or a
+regular ldap server, e.g. openldap
+
+The location of the ldap server is specified in two parameters: 'host' and
+'port'. 'host' can be either a plain hostname or an ldap URI, including the
+protocol, the host and optionally the port, e.g. ldap://localhost:389. In case
+of an URI the port in the configuration must remain empty.
+
+The authentication itself is a two step process which differs, depending on how
+to bind to the server. If the configuration sets 'bindDN' and 'bindPW', those
+values will be used for a initial non anonymous bind to the ldap server
+otherwise an anonymous bind is executed.
+
+After the initial bind, a ldap search for either 'uid=' (ldap) or
+'sAMAccountName=' (AD) below basedn is done. The purpose of this
+search is to retrieve a working bindDN which is then used to actually
+authenticate the user. In case of an anonymous first bind the search will
+likely fail and the bindDN for the second bind will be either
+'uid=,' (ldap) or '@' (AD). If
+the search succeeds the bindDN will be taken from the user's data in the ldap
+server. This bindDN will be used for a second bind using the users password.
+If the second bind succeeds the user could be successfully authenticated.
+
+The data from the ldap server can be used to create an account in SeedDMS
+if the user trying to login does not exist yet, but was able to authenticate.
+This will only be done if 'authentication->restricted' in the configuration
+is set to true. In that case the common name (cn) and email address is taken
+from ldap. Existing accounts in SeedDMS will not be updated with data from
+ldap.
+
+Examples
+---------
+
+Anonymous bind to openldap on localhost, port 389
+- type = "ldap"
+- baseDN = "ou=users,dc=mycompany,dc=de"
+- host = "ldap://localhost"
+
+During authentication as user 'admin' the following steps are executed
+
+1. connect to ldap server at localhost:389
+2. do an anonymous bind
+3. search for 'uid=admin' below basedn
+4.1. if search succeeds use the dn from the user
+4.2. if search fails use 'uid=admin,' as dn
+5. do a non anonymous bind with dn and password entered by user
+6. if step 5. succeeds the use is authenticated
+
+If bindDN and bindPW are specified in the configuration, the second step
+will be a non anonymous bind.
+
diff --git a/doc/README.Mail b/doc/README.Mail
new file mode 100644
index 000000000..2ee7c999d
--- /dev/null
+++ b/doc/README.Mail
@@ -0,0 +1,30 @@
+Mail configuration
+===================
+
+SeedDMS uses email to
+
+* notify users about changes of documents and folders
+* send instructions during the password forgotten process
+
+Configuring email in SeedDMS is simple on systems running a
+local mail server, because this is the default in SeedDMS and
+no additional configuration is needed. On Linux you should
+consider running a local mail server, which relais the mails
+to your outgoing mail server. If you cannot run a local mail
+server, you can still configure SeedDMS to use an outgoing
+SMTP server. Below are some examples on how to configure
+SeedDMS for different hosters.
+
+1&1
+---------
+
+smtp server: ssl://smtp.1und1.de
+smtp port: 465
+
+Gmail
+---------
+smtp server: smtp.gmail.com
+smtp port: 587
+note: you have to turn on 'Less secure app access' in your google account,
+otherwise you will not be able to send mail. It will quit with an error
+complaining about wrong credentials
diff --git a/doc/README.ocr b/doc/README.ocr
new file mode 100644
index 000000000..aaf6a9196
--- /dev/null
+++ b/doc/README.ocr
@@ -0,0 +1,59 @@
+OCR
+====
+
+SeedDMS itself has no support for optical character recognition (OCR)
+because it does not care about the content of file. Though, external
+OCR software can be used to convert an image into text and index it
+by the full text search engine.
+
+The following script can be use to convert a scanned image into pdf
+with a text layer added. The script actually takes this file to
+ran it through pdftotext. It was published in the seeddms forum
+https://sourceforge.net/p/seeddms/discussion/general/thread/4ec5973d/
+
+
+#!/bin/bash
+inputpdf=$1
+temp_folder=/tmp/seedinput/$(date +"%Y_%m_%d_%H%M%S")/
+lockfile=/tmp/seed
+protokolldatei=./tesser_syslog
+cores=2
+
+mkdir -p $lockfile
+
+while [ -e "$lockfile"/"`basename $0`" ];
+do
+ sleep 5
+done
+
+if ( set -o noclobber; echo "locked" > "$lockfile"/"`basename $0`"); then
+
+trap 'rm -f "$lockfile"/"`basename $0`"; echo $(date) " Lockdatei wird geloescht: " $lockfile"/"`basename $0` Aufrufparameter: $* >> $protokolldatei ;rm -r $temp_folder; exit $?' INT TERM KILL EXIT
+ #das Datum mit dem Scriptnamen in die Protokolldatei schreiben
+ echo $(date) " Lockdatei erstellt: " $lockfile"/"`basename $0` >> $protokolldatei
+
+else
+ #Script beenden falls Lockdatei nicht erstellt werden konnte
+ echo $(date) " Programm wird beendet, Lockdatei konnte nicht erstellt werden: $lockfile"/"`basename $0` Aufrufparameter: $* " >> $protokolldatei
+ exit 1
+fi
+
+mkdir -p $temp_folder
+
+$(pdftotext -raw $1 - 1> $temp_folder''tmp.txt )
+pdf_contents=`cat $temp_folder''tmp.txt`
+pdf_contents=`echo "$pdf_contents" | tr -dc '[:print:]'`
+if [ -z "$pdf_contents" ]; then
+ convert -density 300 -quality 95 $inputpdf +adjoin $temp_folder''image%03d.jpg
+ find $temp_folder -name '*.jpg'| parallel --gnu -j $cores tesseract -l deu --psm 6 {} {} pdf
+
+num=`find $temp_folder -name '*.pdf'| wc -l`
+if [ "$num" -gt "1" ]; then
+ pdfunite $temp_folder*.pdf $temp_folder''tmp.pdf
+else
+ mv $temp_folder*.pdf $temp_folder''tmp.pdf
+fi
+ pdftotext $temp_folder''tmp.pdf $temp_folder''tmp.txt
+ mv $temp_folder''tmp.pdf $1
+fi
+cat $temp_folder''tmp.txt
diff --git a/inc/inc.ClassController.php b/inc/inc.ClassController.php
index 2092d9313..a6ebc1936 100644
--- a/inc/inc.ClassController.php
+++ b/inc/inc.ClassController.php
@@ -30,7 +30,7 @@ class Controller {
* @return object an object of a class implementing the view
*/
static function factory($class, $params=array()) { /* {{{ */
- global $settings, $session, $extMgr;
+ global $settings, $session, $extMgr, $request;
if(!$class) {
return null;
}
@@ -56,6 +56,7 @@ class Controller {
$controller->setParam('getVars', $_GET);
$controller->setParam('requestVars', $_REQUEST);
$controller->setParam('session', $session);
+ $controller->setParam('request', $request);
$controller->setParam('settings', $settings);
return $controller;
}
diff --git a/inc/inc.ClassControllerCommon.php b/inc/inc.ClassControllerCommon.php
index 403f18518..2f7d1afa4 100644
--- a/inc/inc.ClassControllerCommon.php
+++ b/inc/inc.ClassControllerCommon.php
@@ -41,37 +41,56 @@ class SeedDMS_Controller_Common {
*/
protected $lasthookresult;
- function __construct($params) {
+ public function __construct($params) {
$this->params = $params;
$this->error = 0;
$this->errormsg = '';
}
/**
- * Call methods with name in $get['action']
+ * Call method with name in $get['action']
*
- * @params array $get $_GET or $_POST variables
+ * Until 5.1.26 (6.0.19) this method took the name of the
+ * controller method to run from the element 'action' passed
+ * in the array $get. Since 5.1.27 (6.0.20) a PSR7 Request
+ * object is available in the controller and used to get the
+ * action.
+ *
+ * @params array $get $_GET or $_POST variables (since 5.1.27 this is no longer used)
* @return mixed return value of called method
*/
- function __invoke($get=array()) {
- $this->callHook('preRun', isset($get['action']) ? $get['action'] : 'run');
- if(isset($get['action']) && $get['action']) {
- if(method_exists($this, $get['action'])) {
- return $this->{$get['action']}();
- } else {
- echo "Missing action '".$get['action']."'";
- return false;
+ public function __invoke($get=array()) {
+ $action = null;
+ if(!$action = $this->getParam('action')) {
+ $request = $this->getParam('request');
+ if($request) {
+ if($request->isMethod('get'))
+ $action = $request->query->get('action');
+ elseif($request->isMethod('post'))
+ $action = $request->request->get('action');
}
- } else
- return $this->run();
- $this->callHook('postRun', isset($get['action']) ? $get['action'] : 'run');
+ }
+ if(!$this->callHook('preRun', get_class($this), $action ? $action : 'run')) {
+ if($action) {
+ if(method_exists($this, $action)) {
+ return $this->{$action}();
+ } else {
+ echo "Missing action '".$action."'";
+ return false;
+ }
+ } else
+ return $this->run();
+ } else {
+ return false;
+ }
+ $this->callHook('postRun', get_class($this), $action ? $action : 'run');
}
- function setParams($params) {
+ public function setParams($params) {
$this->params = $params;
}
- function setParam($name, $value) {
+ public function setParam($name, $value) {
$this->params[$name] = $value;
}
@@ -85,7 +104,7 @@ class SeedDMS_Controller_Common {
* @param string $name name of parameter
* @return mixed value of parameter or null if parameter does not exist
*/
- function getParam($name) {
+ public function getParam($name) {
return isset($this->params[$name]) ? $this->params[$name] : null;
}
@@ -95,7 +114,7 @@ class SeedDMS_Controller_Common {
* @param string $name name of parameter
* @return boolean true if parameter exists otherwise false
*/
- function hasParam($name) {
+ public function hasParam($name) {
return isset($this->params[$name]) ? true : false;
}
@@ -104,12 +123,12 @@ class SeedDMS_Controller_Common {
*
* @param string $name name of parameter
*/
- function unsetParam($name) {
+ public function unsetParam($name) {
if(isset($this->params[$name]))
unset($this->params[$name]);
}
- function run() {
+ public function run() {
}
/**
diff --git a/inc/inc.ClassConversionMgr.php b/inc/inc.ClassConversionMgr.php
index 5ad9be70a..278d2e510 100644
--- a/inc/inc.ClassConversionMgr.php
+++ b/inc/inc.ClassConversionMgr.php
@@ -13,6 +13,7 @@
require_once("inc/inc.ClassConversionServiceExec.php");
require_once("inc/inc.ClassConversionServiceImageToImage.php");
+require_once("inc/inc.ClassConversionServiceImageToText.php");
require_once("inc/inc.ClassConversionServicePdfToImage.php");
require_once("inc/inc.ClassConversionServiceTextToText.php");
diff --git a/inc/inc.ClassConversionServiceImageToImage.php b/inc/inc.ClassConversionServiceImageToImage.php
index 952efc4f0..b5c9e7951 100644
--- a/inc/inc.ClassConversionServiceImageToImage.php
+++ b/inc/inc.ClassConversionServiceImageToImage.php
@@ -28,15 +28,15 @@ class SeedDMS_ConversionServiceImageToImage extends SeedDMS_ConversionServiceBas
*/
public $timeout;
- public function __construct($from, $to) {
+ public function __construct($from, $to) { /* {{{ */
$this->from = $from;
$this->to = $to;
$this->timeout = 5;
- }
+ } /* }}} */
- public function getInfo() {
- return "Convert with imagick php functions";
- }
+ public function getInfo() { /* {{{ */
+ return "Convert with imagick or gd php functions";
+ } /* }}} */
public function getAdditionalParams() { /* {{{ */
return [
@@ -44,28 +44,68 @@ class SeedDMS_ConversionServiceImageToImage extends SeedDMS_ConversionServiceBas
];
} /* }}} */
- public function convert($infile, $target = null, $params = array()) {
+ /**
+ * Convert a pixel image into png and scale it
+ *
+ * This method uses imagick and if not available falls back to the gd library.
+ */
+ public function convert($infile, $target = null, $params = array()) { /* {{{ */
$start = microtime(true);
- $imagick = new Imagick();
- try {
- if($imagick->readImage($infile)) {
+ if(extension_loaded('imagick')) {
+ $imagick = new Imagick();
+ try {
+ if($imagick->readImage($infile)) {
+ if(!empty($params['width']))
+ $imagick->scaleImage(min((int) $params['width'], $imagick->getImageWidth()), 0);
+ $end = microtime(true);
+ if($this->logger) {
+ $this->logger->log('Conversion from '.$this->from.' to '.$this->to.' with imagick service took '.($end-$start).' sec.', PEAR_LOG_INFO);
+ }
+ if($target) {
+ return $imagick->writeImage($target);
+ } else {
+ return $imagick->getImageBlob();
+ }
+ }
+ } catch (ImagickException $e) {
+ return false;
+ }
+ } elseif(extension_loaded('gd')) {
+ $im = null;
+ switch($this->from) {
+ case 'image/jpeg':
+ case 'image/jpg':
+ $im = @imagecreatefromjpeg($infile);
+ break;
+ case 'image/png':
+ $im = @imagecreatefrompng($infile);
+ break;
+ case 'image/gif':
+ $im = @imagecreatefromgif($infile);
+ break;
+ }
+ if($im) {
+ $size = getimagesize($infile);
if(!empty($params['width']))
- $imagick->scaleImage(min((int) $params['width'], $imagick->getImageWidth()), 0);
+ $im = imagescale($im, min((int) $params['width'], $size[0]));
$end = microtime(true);
if($this->logger) {
- $this->logger->log('Conversion from '.$this->from.' to '.$this->to.' with image service took '.($end-$start).' sec.', PEAR_LOG_INFO);
+ $this->logger->log('Conversion from '.$this->from.' to '.$this->to.' with gd image service took '.($end-$start).' sec.', PEAR_LOG_INFO);
}
if($target) {
- return $imagick->writeImage($target);
+ return imagepng($im, $target);
} else {
- return $imagick->getImageBlob();
+ ob_start();
+ var_dump(imagepng($im));
+ $image = ob_get_clean();
+ return $image;
}
+ } else {
+ return false;
}
- } catch (ImagickException $e) {
- return false;
}
return false;
- }
+ } /* }}} */
}
diff --git a/inc/inc.ClassConversionServiceImageToText.php b/inc/inc.ClassConversionServiceImageToText.php
new file mode 100644
index 000000000..326dba28c
--- /dev/null
+++ b/inc/inc.ClassConversionServiceImageToText.php
@@ -0,0 +1,75 @@
+
+ * @copyright Copyright (C) 2021 Uwe Steinmann
+ * @version Release: @package_version@
+ */
+
+require_once("inc/inc.ClassConversionServiceBase.php");
+
+/**
+ * Implementation of conversion service image class
+ *
+ * @category DMS
+ * @package SeedDMS
+ * @author Uwe Steinmann
+ * @copyright Copyright (C) 2021 Uwe Steinmann
+ * @version Release: @package_version@
+ */
+class SeedDMS_ConversionServiceImageToText extends SeedDMS_ConversionServiceBase {
+ /**
+ * timeout
+ */
+ public $timeout;
+
+ public function __construct($from, $to) { /* {{{ */
+ $this->from = $from;
+ $this->to = $to;
+ } /* }}} */
+
+ public function getInfo() { /* {{{ */
+ return "Convert by extracting iptc data";
+ } /* }}} */
+
+ public function getAdditionalParams() { /* {{{ */
+ return [
+ ];
+ } /* }}} */
+
+ /**
+ * Convert a pixel image into text by reading the iptc data
+ *
+ * This method uses getimagesize() to extract the data.
+ */
+ public function convert($infile, $target = null, $params = array()) { /* {{{ */
+ $start = microtime(true);
+ $imsize = getimagesize($infile, $moreinfo);
+ if(!empty($moreinfo['APP13'])) {
+ $txt = '';
+ $iptcdata = iptcparse($moreinfo['APP13']);
+ foreach(['2#005', '2#015', '2#025', '2#105', '2#080', '2#115', '2#120'] as $key) {
+ if(isset($iptcdata[$key]))
+ $txt .= implode(' ', $iptcdata[$key])."\n";
+ }
+ $end = microtime(true);
+ if($this->logger) {
+ $this->logger->log('Conversion from '.$this->from.' to '.$this->to.' by extracting iptc took '.($end-$start).' sec.', PEAR_LOG_INFO);
+ }
+ if($target) {
+ file_put_contents($target, $txt);
+ return true;
+ } else {
+ return $txt;
+ }
+ }
+ return false;
+ } /* }}} */
+}
+
+
diff --git a/inc/inc.ClassDownloadMgr.php b/inc/inc.ClassDownloadMgr.php
new file mode 100644
index 000000000..1958e652e
--- /dev/null
+++ b/inc/inc.ClassDownloadMgr.php
@@ -0,0 +1,230 @@
+
+ * @copyright 2015 Uwe Steinmann
+ * @version Release: @package_version@
+ */
+
+#require_once("PHPExcel.php");
+require_once("vendor/autoload.php");
+
+/**
+ * Class to represent an download manager
+ *
+ * This class provides some very basic methods to download document lists.
+ *
+ * @category DMS
+ * @package SeedDMS
+ * @author Uwe Steinmann
+ * @copyright 2015 Uwe Steinmann
+ * @version Release: @package_version@
+ */
+class SeedDMS_Download_Mgr {
+ /**
+ * @var string $tmpdir directory where download archive is temp. created
+ * @access protected
+ */
+ protected $tmpdir;
+
+ /**
+ * @var array $items list of document content items
+ * @access protected
+ */
+ protected $items;
+
+ /**
+ * @var array $extracols list of arrays with extra columns per item
+ * @access protected
+ */
+ protected $extracols;
+
+ /**
+ * @var array $rawcontents list of content used instead of document content
+ * @access protected
+ */
+ protected $rawcontents;
+
+ /**
+ * @var array $filenames filename used in archive
+ * @access protected
+ */
+ protected $filnames;
+
+ function __construct($tmpdir = '') {
+ $this->tmpdir = $tmpdir;
+ $this->items = array();
+ $this->header = array(getMLText('download_header_document_no'), getMLText('download_header_document_name'), getMLText('download_header_filename'), getMLText('download_header_state'), getMLText('download_header_internal_version'), getMLText('download_header_reviewer'), getMLText('download_header_review_date'), getMLText('download_header_review_comment'), getMLText('download_header_review_state'), getMLText('download_header_approver'), getMLText('download_header_approval_date'), getMLText('download_header_approval_comment'), getMLText('download_header_approval_state'));
+ $this->extracols = array();
+ $this->rawcontents = array();
+ $this->extraheader = array();
+ }
+
+ public function addHeader($extraheader) { /* {{{ */
+ $this->extraheader = $extraheader;
+ } /* }}} */
+
+ public function addItem($item, $extracols=array(), $rawcontent='', $filename='') { /* {{{ */
+ $this->items[$item->getID()] = $item;
+ $this->extracols[$item->getID()] = $extracols;
+ $this->rawcontents[$item->getID()] = $rawcontent;
+ $this->filenames[$item->getID()] = $filename;
+ } /* }}} */
+
+ public function createToc($file) { /* {{{ */
+ $items = $this->items;
+ $objPHPExcel = new PhpOffice\PhpSpreadsheet\Spreadsheet();
+ $objPHPExcel->getProperties()->setCreator("SeedDMS")->setTitle("Metadata");
+ $sheet = $objPHPExcel->setActiveSheetIndex(0);
+
+ $i = 1;
+ $col = 0;
+ foreach($this->header as $h)
+ $sheet->setCellValueByColumnAndRow($col++, $i, $h);
+ foreach($this->extraheader as $h)
+ $sheet->setCellValueByColumnAndRow($col++, $i, $h);
+ $i++;
+ foreach($items as $item) {
+ $document = $item->getDocument();
+ $dms = $document->_dms;
+ $status = $item->getStatus();
+ $reviewStatus = $item->getReviewStatus();
+ $approvalStatus = $item->getApprovalStatus();
+
+ $col = 0;
+ $sheet->setCellValueByColumnAndRow($col++, $i, $document->getID());
+ $sheet->setCellValueByColumnAndRow($col++, $i, $document->getName());
+ $sheet->setCellValueByColumnAndRow($col++, $i, $document->getID()."-".$item->getOriginalFileName());
+ $sheet->setCellValueByColumnAndRow($col++, $i, getOverallStatusText($status['status']));
+ $sheet->setCellValueByColumnAndRow($col++, $i, $item->getVersion());
+ $l = $i;
+ $k = $i;
+ if($reviewStatus) {
+ foreach ($reviewStatus as $r) {
+ switch ($r["type"]) {
+ case 0: // Reviewer is an individual.
+ $required = $dms->getUser($r["required"]);
+ if (!is_object($required)) {
+ $reqName = getMLText("unknown_user")." '".$r["required"]."'";
+ } else {
+ $reqName = htmlspecialchars($required->getFullName()." (".$required->getLogin().")");
+ }
+ break;
+ case 1: // Reviewer is a group.
+ $required = $dms->getGroup($r["required"]);
+ if (!is_object($required)) {
+ $reqName = getMLText("unknown_group")." '".$r["required"]."'";
+ } else {
+ $reqName = htmlspecialchars($required->getName());
+ }
+ break;
+ }
+ $tcol = $col;
+ $sheet->setCellValueByColumnAndRow($tcol++, $l, $reqName);
+ $sheet->setCellValueByColumnAndRow($tcol, $l, ($r['status']==1 || $r['status']==-1) ? PHPExcel_Shared_Date::PHPToExcel(new DateTime($r['date'])) : null);
+ $sheet->getStyleByColumnAndRow($tcol++, $l)->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX22);
+ $sheet->setCellValueByColumnAndRow($tcol++, $l, $r['comment']);
+ $sheet->setCellValueByColumnAndRow($tcol++, $l, getReviewStatusText($r["status"]));
+ $l++;
+ }
+ $l--;
+ }
+ $col += 4;
+ if($approvalStatus) {
+ foreach ($approvalStatus as $r) {
+ switch ($r["type"]) {
+ case 0: // Reviewer is an individual.
+ $required = $dms->getUser($r["required"]);
+ if (!is_object($required)) {
+ $reqName = getMLText("unknown_user")." '".$r["required"]."'";
+ } else {
+ $reqName = htmlspecialchars($required->getFullName()." (".$required->getLogin().")");
+ }
+ break;
+ case 1: // Reviewer is a group.
+ $required = $dms->getGroup($r["required"]);
+ if (!is_object($required)) {
+ $reqName = getMLText("unknown_group")." '".$r["required"]."'";
+ } else {
+ $reqName = htmlspecialchars($required->getName());
+ }
+ break;
+ }
+ $tcol = $col;
+ $sheet->setCellValueByColumnAndRow($tcol++, $k, $reqName);
+ $sheet->setCellValueByColumnAndRow($tcol, $k, ($r['status']==1 || $r['status']==-1) ?PHPExcel_Shared_Date::PHPToExcel(new DateTime($r['date'])) : null);
+ $sheet->getStyleByColumnAndRow($tcol++, $k)->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX22);
+ $sheet->setCellValueByColumnAndRow($tcol++, $k, $r['comment']);
+ $sheet->setCellValueByColumnAndRow($tcol++, $k, getApprovalStatusText($r["status"]));
+ $k++;
+ }
+ $k--;
+ }
+ $col += 4;
+ if(isset($this->extracols[$item->getID()]) && $this->extracols[$item->getID()]) {
+ foreach($this->extracols[$item->getID()] as $column)
+ $sheet->setCellValueByColumnAndRow($col++, $i, is_array($column) ? implode("\n", $column) : $column );
+ }
+ $i = max($l, $k);
+ $i++;
+ }
+
+ $objWriter = new PhpOffice\PhpSpreadsheet\Writer\Xlsx($objPHPExcel);
+ $objWriter->save($file);
+
+ return true;
+ } /* }}} */
+
+ public function createArchive($filename) { /* {{{ */
+ if(!$this->items) {
+ return false;
+ }
+
+ $file = tempnam(sys_get_temp_dir(), "export-list-");
+ if(!$file)
+ return false;
+ $this->createToc($file);
+
+ $zip = new ZipArchive();
+ $prefixdir = date('Y-m-d', time());
+
+ if(($errcode = $zip->open($filename, ZipArchive::OVERWRITE)) !== TRUE) {
+ echo $errcode;
+ return false;
+ }
+
+ foreach($this->items as $item) {
+ $document = $item->getDocument();
+ $dms = $document->_dms;
+ if($this->filenames[$item->getID()]) {
+ $filename = $this->filenames[$item->getID()];
+ } else {
+ $ext = pathinfo($document->getName(), PATHINFO_EXTENSION);
+ $oext = pathinfo($item->getOriginalFileName(), PATHINFO_EXTENSION);
+ if($ext == $oext)
+ $filename = preg_replace('/[^A-Za-z0-9_.-]/', '_', $document->getName());
+ else {
+ $filename = preg_replace('/[^A-Za-z0-9_-]/', '_', $document->getName()).'.'.$oext;
+ }
+ $filename = $document->getID().'-'.$item->getVersion().'-'.$filename; //$lc->getOriginalFileName();
+ }
+ $filename = $prefixdir."/".$filename;
+ if($this->rawcontents[$item->getID()]) {
+ $zip->addFromString(utf8_decode($filename), $this->rawcontents[$item->getID()]);
+ } else
+ $zip->addFile($dms->contentDir.$item->getPath(), utf8_decode($filename));
+ }
+
+ $zip->addFile($file, $prefixdir."/metadata.xlsx");
+ $zip->close();
+ unlink($file);
+ return true;
+ } /* }}} */
+}
diff --git a/inc/inc.ClassLdapAuthentication.php b/inc/inc.ClassLdapAuthentication.php
index 402347f18..a62ff280d 100644
--- a/inc/inc.ClassLdapAuthentication.php
+++ b/inc/inc.ClassLdapAuthentication.php
@@ -55,7 +55,7 @@ class SeedDMS_LdapAuthentication extends SeedDMS_Authentication {
/* Check if ldap base dn is set, and use ldap server if it is */
if (isset($settings->_ldapBaseDN)) {
$ldapSearchAttribut = "uid=";
- $tmpDN = "cn=".$username.",".$settings->_ldapBaseDN;
+ $tmpDN = "uid=".$username.",".$settings->_ldapBaseDN;
}
/* Active directory has a different base dn */
@@ -127,6 +127,7 @@ class SeedDMS_LdapAuthentication extends SeedDMS_Authentication {
if (!is_bool($search)) {
$info = ldap_get_entries($ds, $search);
+
if (!is_bool($info) && $info["count"]==1 && $info[0]["count"]>0) {
$user = $dms->addUser($username, null, $info[0]['cn'][0], $info[0]['mail'][0], $settings->_language, $settings->_theme, "", 0);
}
diff --git a/inc/inc.ClassUI.php b/inc/inc.ClassUI.php
index b8f4de275..e29b69523 100644
--- a/inc/inc.ClassUI.php
+++ b/inc/inc.ClassUI.php
@@ -45,7 +45,7 @@ class UI extends UI_Default {
* @return object an object of a class implementing the view
*/
static function factory($theme, $class='', $params=array()) { /* {{{ */
- global $settings, $session, $extMgr;
+ global $settings, $session, $extMgr, $request;
if(!$class) {
$class = 'Bootstrap';
$class = 'Style';
@@ -126,6 +126,7 @@ class UI extends UI_Default {
$view->setParam('theme', $theme);
$view->setParam('class', $class);
$view->setParam('session', $session);
+ $view->setParam('request', $request);
// $view->setParam('settings', $settings);
$view->setParam('sitename', $settings->_siteName);
$view->setParam('rootfolderid', $settings->_rootFolderID);
diff --git a/inc/inc.ClassViewCommon.php b/inc/inc.ClassViewCommon.php
index 28a268831..05021234f 100644
--- a/inc/inc.ClassViewCommon.php
+++ b/inc/inc.ClassViewCommon.php
@@ -45,17 +45,40 @@ class SeedDMS_View_Common {
$this->imgpath = '../views/'.$theme.'/images/';
}
+ /**
+ * Call method with name in $get['action']
+ *
+ * Until 5.1.26 (6.0.19) this method took the name of the
+ * controller method to run from the element 'action' passed
+ * in the array $get. Since 5.1.27 (6.0.20) a PSR7 Request
+ * object is available in the controller and used to get the
+ * action.
+ *
+ * @params array $get $_GET or $_POST variables (since 5.1.27 this is no longer used)
+ * @return mixed return value of called method
+ */
public function __invoke($get=array()) {
- $this->callHook('preRun', isset($get['action']) ? $get['action'] : 'show');
- if(isset($get['action']) && $get['action']) {
- if(method_exists($this, $get['action'])) {
- $this->{$get['action']}();
- } else {
- echo "Missing action '".htmlspecialchars($get['action'])."'";
- }
- } else
- $this->show();
- $this->callHook('postRun', isset($get['action']) ? $get['action'] : 'show');
+ $action = null;
+ $request = $this->getParam('request');
+ if($request) {
+ if($request->isMethod('get'))
+ $action = $request->query->get('action');
+ elseif($request->isMethod('post'))
+ $action = $request->request->get('action');
+ }
+ if(!$this->callHook('preRun', get_class($this), $action ? $action : 'show')) {
+ if($action) {
+ if(method_exists($this, $action)) {
+ $this->{$action}();
+ } else {
+ echo "Missing action '".htmlspecialchars($action)."'";
+ }
+ } else
+ $this->show();
+ } else {
+ return false;
+ }
+ $this->callHook('postRun', $action ? $action : 'show');
}
public function setParams($params) {
@@ -78,7 +101,7 @@ class SeedDMS_View_Common {
* @param string $name name of parameter
* @return boolean true if parameter exists otherwise false
*/
- function hasParam($name) {
+ public function hasParam($name) {
return isset($this->params[$name]) ? true : false;
}
diff --git a/inc/inc.ConversionInit.php b/inc/inc.ConversionInit.php
index 1acb3d12a..a1ccb56e6 100644
--- a/inc/inc.ConversionInit.php
+++ b/inc/inc.ConversionInit.php
@@ -21,14 +21,21 @@ if(!empty($settings->_converters['fulltext'])) {
}
}
-$conversionmgr->addService(new SeedDMS_ConversionServicePdfToImage('application/pdf', 'image/png'))->setLogger($logger);
+if(extension_loaded('imagick')) {
+ $conversionmgr->addService(new SeedDMS_ConversionServicePdfToImage('application/pdf', 'image/png'))->setLogger($logger);
+ $conversionmgr->addService(new SeedDMS_ConversionServiceImageToImage('image/tiff', 'image/png'))->setLogger($logger);
+ $conversionmgr->addService(new SeedDMS_ConversionServiceImageToImage('image/svg+xml', 'image/png'))->setLogger($logger);
+}
-$conversionmgr->addService(new SeedDMS_ConversionServiceImageToImage('image/jpeg', 'image/png'))->setLogger($logger);
-$conversionmgr->addService(new SeedDMS_ConversionServiceImageToImage('image/png', 'image/png'))->setLogger($logger);
-$conversionmgr->addService(new SeedDMS_ConversionServiceImageToImage('image/jpg', 'image/png'))->setLogger($logger);
-$conversionmgr->addService(new SeedDMS_ConversionServiceImageToImage('image/gif', 'image/png'))->setLogger($logger);
-$conversionmgr->addService(new SeedDMS_ConversionServiceImageToImage('image/tiff', 'image/png'))->setLogger($logger);
-$conversionmgr->addService(new SeedDMS_ConversionServiceImageToImage('image/svg+xml', 'image/png'))->setLogger($logger);
+if(extension_loaded('gd') || extension_loaded('imagick')) {
+ $conversionmgr->addService(new SeedDMS_ConversionServiceImageToImage('image/jpeg', 'image/png'))->setLogger($logger);
+ $conversionmgr->addService(new SeedDMS_ConversionServiceImageToImage('image/png', 'image/png'))->setLogger($logger);
+ $conversionmgr->addService(new SeedDMS_ConversionServiceImageToImage('image/jpg', 'image/png'))->setLogger($logger);
+ $conversionmgr->addService(new SeedDMS_ConversionServiceImageToImage('image/gif', 'image/png'))->setLogger($logger);
+}
+
+$conversionmgr->addService(new SeedDMS_ConversionServiceImageToText('image/jpeg', 'text/plain'))->setLogger($logger);
+$conversionmgr->addService(new SeedDMS_ConversionServiceImageToText('image/jpg', 'text/plain'))->setLogger($logger);
$conversionmgr->addService(new SeedDMS_ConversionServiceTextToText('text/plain', 'text/plain'))->setLogger($logger);
diff --git a/inc/inc.Init.php b/inc/inc.Init.php
index 2336a7344..69ed0c6a4 100644
--- a/inc/inc.Init.php
+++ b/inc/inc.Init.php
@@ -18,8 +18,11 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+use Symfony\Component\HttpFoundation\Request;
+
if(!empty($settings->_coreDir))
require_once($settings->_coreDir.'/Core.php');
else
require_once('SeedDMS/Core.php');
+$request = Request::createFromGlobals();
diff --git a/inc/inc.Settings.php b/inc/inc.Settings.php
index 3014536ce..83688f255 100644
--- a/inc/inc.Settings.php
+++ b/inc/inc.Settings.php
@@ -64,9 +64,6 @@ ini_set('include_path', $settings->_rootDir.'pear'. PATH_SEPARATOR .ini_get('inc
if(!empty($settings->_extraPath)) {
ini_set('include_path', $settings->_extraPath. PATH_SEPARATOR .ini_get('include_path'));
}
-/* composer is installed in pear directory, but install tool does not need it */
-if(!defined("SEEDDMS_INSTALL"))
- require_once $settings->_rootDir.'../pear/vendor/autoload.php';
if(isset($settings->_maxExecutionTime)) {
if (php_sapi_name() !== "cli") {
@@ -74,22 +71,6 @@ if(isset($settings->_maxExecutionTime)) {
}
}
-if (function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) {
- $process = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
- while (list($key, $val) = each($process)) {
- foreach ($val as $k => $v) {
- unset($process[$key][$k]);
- if (is_array($v)) {
- $process[$key][stripslashes($k)] = $v;
- $process[] = &$process[$key][stripslashes($k)];
- } else {
- $process[$key][stripslashes($k)] = stripslashes($v);
- }
- }
- }
- unset($process);
-}
-
/* Add root Dir. Needed because the view classes are included
* relative to it.
*/
@@ -98,3 +79,7 @@ ini_set('include_path', $settings->_rootDir. PATH_SEPARATOR .ini_get('include_pa
* relative to it.
*/
ini_set('include_path', $settings->_rootDir.'../pear'. PATH_SEPARATOR .ini_get('include_path'));
+
+/* composer is installed in pear directory, but install tool does not need it */
+if(!defined("SEEDDMS_INSTALL"))
+ require_once 'vendor/autoload.php';
diff --git a/inc/inc.Utils.php b/inc/inc.Utils.php
index cfe4c7cef..d54bd0439 100644
--- a/inc/inc.Utils.php
+++ b/inc/inc.Utils.php
@@ -166,53 +166,6 @@ function getReadableDurationArray($secs) { /* {{{ */
return $units;
} /* }}} */
-//
-// The original string sanitizer, kept for reference.
-//function sanitizeString($string) {
-// $string = str_replace("'", "'", $string);
-// $string = str_replace("--", "", $string);
-// $string = str_replace("<", "<", $string);
-// $string = str_replace(">", ">", $string);
-// $string = str_replace("/*", "", $string);
-// $string = str_replace("*/", "", $string);
-// $string = str_replace("\"", """, $string);
-//
-// return $string;
-//}
-
-/* Deprecated, do not use anymore */
-function sanitizeString($string) { /* {{{ */
-
- $string = (string) $string;
- if (get_magic_quotes_gpc()) {
- $string = stripslashes($string);
- }
-
- // The following three are against sql injection. They are not
- // needed anymore because strings are quoted propperly when saved into
- // the database.
-// $string = str_replace("\\", "\\\\", $string);
-// $string = str_replace("--", "\-\-", $string);
-// $string = str_replace(";", "\;", $string);
- // Use HTML entities to represent the other characters that have special
- // meaning in SQL. These can be easily converted back to ASCII / UTF-8
- // with a decode function if need be.
- $string = str_replace("&", "&", $string);
- $string = str_replace("%", "%", $string); // percent
- $string = str_replace("\"", """, $string); // double quote
- $string = str_replace("/*", "/*", $string); // start of comment
- $string = str_replace("*/", "*/", $string); // end of comment
- $string = str_replace("<", "<", $string);
- $string = str_replace(">", ">", $string);
- $string = str_replace("=", "=", $string);
- $string = str_replace(")", ")", $string);
- $string = str_replace("(", "(", $string);
- $string = str_replace("'", "'", $string);
- $string = str_replace("+", "+", $string);
-
- return trim($string);
-} /* }}} */
-
/* Deprecated, do not use anymore, but keep it for upgrading
* older versions
*/
@@ -414,6 +367,34 @@ function utf8_basename($path, $suffix='') { /* {{{ */
return $file;
} /* }}} */
+/**
+ * Return a valid file name
+ *
+ * This function returns a valid file name for the given document content
+ * or an arbitrary string. If a document content is given the name of
+ * the document will be used. The extension of the file name will be
+ * either taken from the document name or the original file. If the two
+ * differ the extension from the original file name will be used.
+ *
+ * @param object|string $content document content or an arbitrary string
+ * @return string valid file name
+ */
+function getFilenameByDocname($content) { /* {{{ */
+ if(is_string) {
+ $filename = $content;
+ } else {
+ $document = $content->getDocument();
+ $ext = pathinfo($document->getName(), PATHINFO_EXTENSION);
+ $oext = pathinfo($content->getOriginalFileName(), PATHINFO_EXTENSION);
+ if($ext == $oext)
+ $filename = $document->getName();
+ else {
+ $filename = $document->getName().'.'.$oext;
+ }
+ }
+ return mb_ereg_replace("([^\w\s\d\-_~,;\[\]\(\).])", '', $filename);
+} /* }}} */
+
function getLogger($prefix='') { /* {{{ */
global $settings;
diff --git a/inc/inc.Version.php b/inc/inc.Version.php
index 08fdd5d5b..4368970f4 100644
--- a/inc/inc.Version.php
+++ b/inc/inc.Version.php
@@ -20,7 +20,7 @@
class SeedDMS_Version { /* {{{ */
- const _number = "5.1.26";
+ const _number = "5.1.27";
const _string = "SeedDMS";
function __construct() {
diff --git a/install/update-1.8.1/update.php b/install/update-1.8.1/update.php
index c1ac6fd2e..9e483850b 100644
--- a/install/update-1.8.1/update.php
+++ b/install/update-1.8.1/update.php
@@ -1,42 +1,42 @@
-