diff --git a/bin/storageverification.php b/bin/storageverification.php index 8469420..b0f071d 100644 --- a/bin/storageverification.php +++ b/bin/storageverification.php @@ -1,148 +1,190 @@ . - * - * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco, + * + * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco, * California 94120-7775, or email info@knowledgetree.com. - * + * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU General Public License version 3. - * + * * In accordance with Section 7(b) of the GNU General Public License version 3, * these Appropriate Legal Notices must retain the display of the "Powered by - * KnowledgeTree" logo and retain the original copyright notice. If the display of the + * KnowledgeTree" logo and retain the original copyright notice. If the display of the * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices - * must display the words "Powered by KnowledgeTree" and retain the original + * must display the words "Powered by KnowledgeTree" and retain the original * copyright notice. * Contributor( s): ______________________________________ */ require_once(dirname(__FILE__) . '/../config/dmsDefaults.php'); -require_once(KT_LIB_DIR . '/dispatcher.inc.php'); -$sectionName = 'Administration'; -require_once(KT_LIB_DIR . '/templating/kt3template.inc.php'); - -require_once(KT_LIB_DIR . '/browse/browseutil.inc.php'); - -class VerifyDispatcher extends KTDispatcher { - function VerifyDispatcher() { - $this->aIgnore = array( - '.', '..', - 'CVS', - '.empty', - '.htaccess', - '.cvsignore', - '.svn', - ); - - $oConfig =& KTConfig::getSingleton(); - $this->fsPath = $oConfig->get('urls/documentRoot'); - - return parent::KTDispatcher(); +require_once(KT_LIB_DIR . '/storage/storagemanager.inc.php'); + +// TODO: this does not verify files that are in the storage system, but not on the database. It is better that the storage system +// be in sync with the database. However, we should have a better way to query the storage driver to give us a list of files. + +class StorageVerification +{ + private $count; + private $lineCount; + private $doc; + const DOCS_PER_DOT = 100; + const DOTS_PER_LINE = 80; + private $nl; + private $tab; + + private + function error($msg) + { + $doc = $this->doc; + $documentId = $doc->getId(); + $path = $doc->getFullPath(); + $filename = $doc->getFileName(); + $storagePath = $doc->getStoragePath(); + + print "{$this->nl}{$this->nl}"; + print "Problem with Document ID: {$documentId}{$this->nl}"; + print "{$this->tab}Path: {$path}{$this->nl}"; + print "{$this->tab}Filename: {$filename}{$this->nl}"; + print "{$this->tab}StoragePath: {$storagePath}{$this->nl}"; + print "{$this->tab}Problem: {$msg}{$this->nl}{$this->nl}"; + flush(); + $this->count = 0; + $this->lineCount = 0; + $this->clearCache(); } - function do_main() { - global $aFoldersToRemove; - global $aFilesToRemove; - global $aRepoDocumentProblems; - global $aRepoFolderProblems; - global $aRepoVersionProblems; + private + function progress() + { + if ($this->count++ % StorageVerification::DOCS_PER_DOT == 0) + { + $this->lineCount++; + print '.'; + flush(); + } + if ($this->lineCount == StorageVerification::DOTS_PER_LINE ) + { + print "{$this->nl}"; + flush(); + $this->lineCount = 0; + } + $this->clearCache(); + } - $this->checkDirectory(''); + private + function clearCache() + { + $metadataid = $this->doc->getMetadataVersionId(); + $contentid = $this->doc->getContentVersionId(); + $iId = $this->doc->getId(); + $cache = KTCache::getSingleton(); + $cache->remove('KTDocumentMetadataVersion/id', $metadataid); + $cache->remove('KTDocumentContentVersion/id', $contentid); + $cache->remove('KTDocumentCore/id', $iId); + $cache->remove('Document/id', $iId); + unset($GLOBALS['_OBJECTCACHE']['KTDocumentMetadataVersion'][$metadataid]); + unset($GLOBALS['_OBJECTCACHE']['KTDocumentContentVersion'][$contentid]); + unset($GLOBALS['_OBJECTCACHE']['KTDocumentCore'][$iId]); + + unset($this->doc); + } - $aDocuments =& Document::getList(); - foreach ($aDocuments as $oDocument) { - $this->checkRepoDocument($oDocument); + public + function run() + { + global $argc; + + if (isset($argc)) + { + $this->nl = "\n"; + $this->tab = "\t"; + print "Storage Verification{$this->nl}"; + print "===================={$this->nl}"; } + else + { + $this->nl = '
'; + $this->tab = '    '; + print "Storage Verification{$this->nl}"; - if (!($this->aFilesToRemove or $this->aRepoDocumentProblems)) { - return; } - $oTemplate =& - $this->oValidator->validateTemplate('ktcore/document/cleanup_script'); - $oTemplate->setData(array( - 'aFilesToRemove' => $this->aFilesToRemove, - 'aRepoDocumentProblems' => $this->aRepoDocumentProblems, - )); - print $oTemplate->render(); - exit(0); - } - function checkDirectory($path) { - $fullpath = sprintf('%s/%s', $this->fsPath, $path); - if (!is_dir($fullpath)) { - print "Not a directory: $fullpath\n"; - } + $sql = "SELECT + dmv.id as metadata_version_id, dcv.document_id, dcv.md5hash, dcv.size + FROM + document_content_version dcv + INNER JOIN document_metadata_version dmv ON dcv.id=dmv.content_version_id"; + $rows = DBUtil::getResultArray($sql); + $this->count = 0; + $this->lineCount = 0; - $dh = @opendir($fullpath); - if ($dh === false) { - print "Could not open directory: $fullpath\n"; - } - while (($filename = readdir($dh)) !== false) { - if (in_array($filename, $this->aIgnore)) { continue; } - $subrelpath = sprintf('%s/%s', $path, $filename); - if (substr($subrelpath, 0, 1) == '/') { - $subrelpath = substr($subrelpath, 1); - } - $subfullpath = sprintf('%s/%s', $this->fsPath, $subrelpath); - if (is_dir($subfullpath)) { - $this->checkDirectory($subrelpath); + $storage =& KTStorageManagerUtil::getSingleton(); + foreach($rows as $row) + { + $doc = Document::get($row['document_id'], $row['metadata_version_id']); + + if (PEAR::isError($doc)) + { + $msg = $doc->getMessage(); + $this->error($doc, "Error with document: {$msg}"); + continue; } - if (is_file($subfullpath)) { - $this->checkFile($subrelpath); + $this->doc = $doc; + + $tmpPath = $storage->temporaryFile($doc); + if (!file_exists($tmpPath)) + { + $this->error("Temporary file could not be resolved: {$tmpPath}"); + continue; } - } - } - function checkFile($path, $first = true) { - $oDocument = KTEntityUtil::getByDict('KTDocumentContentVersion', array( - 'storage_path' => $path, - )); - if (is_a($oDocument, 'ktentitynoobjects')) { - $this->aFilesToRemove[] = $path; - return; - } - } + $expectedSize = $row['size']; + $currentSize = filesize($tmpPath); + if ($expectedSize != $currentSize) + { + $this->error("Filesize does not match. Expected: {$expectedSize} Current: {$currentSize}"); + continue; + } - function checkRepoDocument($oDocument) { - global $aRepoDocumentProblems; - $aDCVs = KTDocumentContentVersion::getByDocument($oDocument); - foreach ($aDCVs as $oDCV) { - $sDocumentPath = $oDCV->getStoragePath(); - $sFullPath = sprintf('%s/%s', $this->fsPath, $sDocumentPath); - if (!is_file($sFullPath)) { - $this->aRepoDocumentProblems[] = array( - 'document' => $oDocument, - 'content' => $oDCV, - 'path' => $sDocumentPath, - 'doclink' => KTBrowseUtil::getUrlForDocument($oDocument), - ); + $expectedHash = $row['md5hash']; + $currentHash = md5_file($tmpPath); + if ($expectedHash != $currentHash) + { + $this->error("Hash does not match. Expected: {$expectedHash} Current: {$currentHash}"); + continue; } + $this->progress(); } + + print "{$this->nl}Done.{$this->nl}{$this->nl}"; } + } -$oDispatcher = new VerifyDispatcher; -$oDispatcher->do_main(); + + +$verification = new StorageVerification(); +$verification->run(); ?>