Commit 6c26629f2311c60ebda581542d7bf8f6a21d4c17
1 parent
5b892972
Merged in from DEV trunk...
KTS-3133 "Error in storage verification process" Updated. Committed By: Conrad Vermeulen Reviewed By: Megan Watson git-svn-id: https://kt-dms.svn.sourceforge.net/svnroot/kt-dms/STABLE/trunk@8890 c91229c3-7414-0410-bfa2-8a42b809f60b
Showing
1 changed file
with
140 additions
and
98 deletions
bin/storageverification.php
| 1 | 1 | <?php |
| 2 | 2 | /** |
| 3 | 3 | * $Id$ |
| 4 | - * | |
| 4 | + * | |
| 5 | 5 | * KnowledgeTree Community Edition |
| 6 | 6 | * Document Management Made Simple |
| 7 | 7 | * Copyright (C) 2008 KnowledgeTree Inc. |
| 8 | 8 | * Portions copyright The Jam Warehouse Software (Pty) Limited |
| 9 | - * | |
| 9 | + * | |
| 10 | 10 | * This program is free software; you can redistribute it and/or modify it under |
| 11 | 11 | * the terms of the GNU General Public License version 3 as published by the |
| 12 | 12 | * Free Software Foundation. |
| 13 | - * | |
| 13 | + * | |
| 14 | 14 | * This program is distributed in the hope that it will be useful, but WITHOUT |
| 15 | 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 16 | 16 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
| 17 | 17 | * details. |
| 18 | - * | |
| 18 | + * | |
| 19 | 19 | * You should have received a copy of the GNU General Public License |
| 20 | 20 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 21 | - * | |
| 22 | - * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco, | |
| 21 | + * | |
| 22 | + * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco, | |
| 23 | 23 | * California 94120-7775, or email info@knowledgetree.com. |
| 24 | - * | |
| 24 | + * | |
| 25 | 25 | * The interactive user interfaces in modified source and object code versions |
| 26 | 26 | * of this program must display Appropriate Legal Notices, as required under |
| 27 | 27 | * Section 5 of the GNU General Public License version 3. |
| 28 | - * | |
| 28 | + * | |
| 29 | 29 | * In accordance with Section 7(b) of the GNU General Public License version 3, |
| 30 | 30 | * these Appropriate Legal Notices must retain the display of the "Powered by |
| 31 | - * KnowledgeTree" logo and retain the original copyright notice. If the display of the | |
| 31 | + * KnowledgeTree" logo and retain the original copyright notice. If the display of the | |
| 32 | 32 | * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices |
| 33 | - * must display the words "Powered by KnowledgeTree" and retain the original | |
| 33 | + * must display the words "Powered by KnowledgeTree" and retain the original | |
| 34 | 34 | * copyright notice. |
| 35 | 35 | * Contributor( s): ______________________________________ |
| 36 | 36 | */ |
| 37 | 37 | |
| 38 | 38 | require_once(dirname(__FILE__) . '/../config/dmsDefaults.php'); |
| 39 | -require_once(KT_LIB_DIR . '/dispatcher.inc.php'); | |
| 40 | -$sectionName = 'Administration'; | |
| 41 | -require_once(KT_LIB_DIR . '/templating/kt3template.inc.php'); | |
| 42 | - | |
| 43 | -require_once(KT_LIB_DIR . '/browse/browseutil.inc.php'); | |
| 44 | - | |
| 45 | -class VerifyDispatcher extends KTDispatcher { | |
| 46 | - function VerifyDispatcher() { | |
| 47 | - $this->aIgnore = array( | |
| 48 | - '.', '..', | |
| 49 | - 'CVS', | |
| 50 | - '.empty', | |
| 51 | - '.htaccess', | |
| 52 | - '.cvsignore', | |
| 53 | - '.svn', | |
| 54 | - ); | |
| 55 | - | |
| 56 | - $oConfig =& KTConfig::getSingleton(); | |
| 57 | - $this->fsPath = $oConfig->get('urls/documentRoot'); | |
| 58 | - | |
| 59 | - return parent::KTDispatcher(); | |
| 39 | +require_once(KT_LIB_DIR . '/storage/storagemanager.inc.php'); | |
| 40 | + | |
| 41 | +// TODO: this does not verify files that are in the storage system, but not on the database. It is better that the storage system | |
| 42 | +// 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. | |
| 43 | + | |
| 44 | +class StorageVerification | |
| 45 | +{ | |
| 46 | + private $count; | |
| 47 | + private $lineCount; | |
| 48 | + private $doc; | |
| 49 | + const DOCS_PER_DOT = 100; | |
| 50 | + const DOTS_PER_LINE = 80; | |
| 51 | + private $nl; | |
| 52 | + private $tab; | |
| 53 | + | |
| 54 | + private | |
| 55 | + function error($msg) | |
| 56 | + { | |
| 57 | + $doc = $this->doc; | |
| 58 | + $documentId = $doc->getId(); | |
| 59 | + $path = $doc->getFullPath(); | |
| 60 | + $filename = $doc->getFileName(); | |
| 61 | + $storagePath = $doc->getStoragePath(); | |
| 62 | + | |
| 63 | + print "{$this->nl}{$this->nl}"; | |
| 64 | + print "Problem with Document ID: {$documentId}{$this->nl}"; | |
| 65 | + print "{$this->tab}Path: {$path}{$this->nl}"; | |
| 66 | + print "{$this->tab}Filename: {$filename}{$this->nl}"; | |
| 67 | + print "{$this->tab}StoragePath: {$storagePath}{$this->nl}"; | |
| 68 | + print "{$this->tab}Problem: {$msg}{$this->nl}{$this->nl}"; | |
| 69 | + flush(); | |
| 70 | + $this->count = 0; | |
| 71 | + $this->lineCount = 0; | |
| 72 | + $this->clearCache(); | |
| 60 | 73 | } |
| 61 | 74 | |
| 62 | - function do_main() { | |
| 63 | - global $aFoldersToRemove; | |
| 64 | - global $aFilesToRemove; | |
| 65 | - global $aRepoDocumentProblems; | |
| 66 | - global $aRepoFolderProblems; | |
| 67 | - global $aRepoVersionProblems; | |
| 75 | + private | |
| 76 | + function progress() | |
| 77 | + { | |
| 78 | + if ($this->count++ % StorageVerification::DOCS_PER_DOT == 0) | |
| 79 | + { | |
| 80 | + $this->lineCount++; | |
| 81 | + print '.'; | |
| 82 | + flush(); | |
| 83 | + } | |
| 68 | 84 | |
| 85 | + if ($this->lineCount == StorageVerification::DOTS_PER_LINE ) | |
| 86 | + { | |
| 87 | + print "{$this->nl}"; | |
| 88 | + flush(); | |
| 89 | + $this->lineCount = 0; | |
| 90 | + } | |
| 91 | + $this->clearCache(); | |
| 92 | + } | |
| 69 | 93 | |
| 70 | - $this->checkDirectory(''); | |
| 94 | + private | |
| 95 | + function clearCache() | |
| 96 | + { | |
| 97 | + $metadataid = $this->doc->getMetadataVersionId(); | |
| 98 | + $contentid = $this->doc->getContentVersionId(); | |
| 99 | + $iId = $this->doc->getId(); | |
| 100 | + $cache = KTCache::getSingleton(); | |
| 101 | + $cache->remove('KTDocumentMetadataVersion/id', $metadataid); | |
| 102 | + $cache->remove('KTDocumentContentVersion/id', $contentid); | |
| 103 | + $cache->remove('KTDocumentCore/id', $iId); | |
| 104 | + $cache->remove('Document/id', $iId); | |
| 105 | + unset($GLOBALS['_OBJECTCACHE']['KTDocumentMetadataVersion'][$metadataid]); | |
| 106 | + unset($GLOBALS['_OBJECTCACHE']['KTDocumentContentVersion'][$contentid]); | |
| 107 | + unset($GLOBALS['_OBJECTCACHE']['KTDocumentCore'][$iId]); | |
| 108 | + | |
| 109 | + unset($this->doc); | |
| 110 | + } | |
| 71 | 111 | |
| 72 | - $aDocuments =& Document::getList(); | |
| 73 | - foreach ($aDocuments as $oDocument) { | |
| 74 | - $this->checkRepoDocument($oDocument); | |
| 112 | + public | |
| 113 | + function run() | |
| 114 | + { | |
| 115 | + global $argc; | |
| 116 | + | |
| 117 | + if (isset($argc)) | |
| 118 | + { | |
| 119 | + $this->nl = "\n"; | |
| 120 | + $this->tab = "\t"; | |
| 121 | + print "Storage Verification{$this->nl}"; | |
| 122 | + print "===================={$this->nl}"; | |
| 75 | 123 | } |
| 124 | + else | |
| 125 | + { | |
| 126 | + $this->nl = '<br>'; | |
| 127 | + $this->tab = ' '; | |
| 128 | + print "<b>Storage Verification</b>{$this->nl}"; | |
| 76 | 129 | |
| 77 | - if (!($this->aFilesToRemove or $this->aRepoDocumentProblems)) { | |
| 78 | - return; | |
| 79 | 130 | } |
| 80 | 131 | |
| 81 | - $oTemplate =& | |
| 82 | - $this->oValidator->validateTemplate('ktcore/document/cleanup_script'); | |
| 83 | - $oTemplate->setData(array( | |
| 84 | - 'aFilesToRemove' => $this->aFilesToRemove, | |
| 85 | - 'aRepoDocumentProblems' => $this->aRepoDocumentProblems, | |
| 86 | - )); | |
| 87 | - print $oTemplate->render(); | |
| 88 | - exit(0); | |
| 89 | - } | |
| 90 | 132 | |
| 91 | - function checkDirectory($path) { | |
| 92 | - $fullpath = sprintf('%s/%s', $this->fsPath, $path); | |
| 93 | 133 | |
| 94 | - if (!is_dir($fullpath)) { | |
| 95 | - print "Not a directory: $fullpath\n"; | |
| 96 | - } | |
| 134 | + $sql = "SELECT | |
| 135 | + dmv.id as metadata_version_id, dcv.document_id, dcv.md5hash, dcv.size | |
| 136 | + FROM | |
| 137 | + document_content_version dcv | |
| 138 | + INNER JOIN document_metadata_version dmv ON dcv.id=dmv.content_version_id"; | |
| 139 | + $rows = DBUtil::getResultArray($sql); | |
| 140 | + $this->count = 0; | |
| 141 | + $this->lineCount = 0; | |
| 97 | 142 | |
| 98 | - $dh = @opendir($fullpath); | |
| 99 | - if ($dh === false) { | |
| 100 | - print "Could not open directory: $fullpath\n"; | |
| 101 | - } | |
| 102 | - while (($filename = readdir($dh)) !== false) { | |
| 103 | - if (in_array($filename, $this->aIgnore)) { continue; } | |
| 104 | - $subrelpath = sprintf('%s/%s', $path, $filename); | |
| 105 | - if (substr($subrelpath, 0, 1) == '/') { | |
| 106 | - $subrelpath = substr($subrelpath, 1); | |
| 107 | - } | |
| 108 | - $subfullpath = sprintf('%s/%s', $this->fsPath, $subrelpath); | |
| 109 | - if (is_dir($subfullpath)) { | |
| 110 | - $this->checkDirectory($subrelpath); | |
| 143 | + $storage =& KTStorageManagerUtil::getSingleton(); | |
| 144 | + foreach($rows as $row) | |
| 145 | + { | |
| 146 | + $doc = Document::get($row['document_id'], $row['metadata_version_id']); | |
| 147 | + | |
| 148 | + if (PEAR::isError($doc)) | |
| 149 | + { | |
| 150 | + $msg = $doc->getMessage(); | |
| 151 | + $this->error($doc, "Error with document: {$msg}"); | |
| 152 | + continue; | |
| 111 | 153 | } |
| 112 | - if (is_file($subfullpath)) { | |
| 113 | - $this->checkFile($subrelpath); | |
| 154 | + $this->doc = $doc; | |
| 155 | + | |
| 156 | + $tmpPath = $storage->temporaryFile($doc); | |
| 157 | + if (!file_exists($tmpPath)) | |
| 158 | + { | |
| 159 | + $this->error("Temporary file could not be resolved: {$tmpPath}"); | |
| 160 | + continue; | |
| 114 | 161 | } |
| 115 | - } | |
| 116 | - } | |
| 117 | 162 | |
| 118 | - function checkFile($path, $first = true) { | |
| 119 | - $oDocument = KTEntityUtil::getByDict('KTDocumentContentVersion', array( | |
| 120 | - 'storage_path' => $path, | |
| 121 | - )); | |
| 122 | - if (is_a($oDocument, 'ktentitynoobjects')) { | |
| 123 | - $this->aFilesToRemove[] = $path; | |
| 124 | - return; | |
| 125 | - } | |
| 126 | - } | |
| 163 | + $expectedSize = $row['size']; | |
| 164 | + $currentSize = filesize($tmpPath); | |
| 165 | + if ($expectedSize != $currentSize) | |
| 166 | + { | |
| 167 | + $this->error("Filesize does not match. Expected: {$expectedSize} Current: {$currentSize}"); | |
| 168 | + continue; | |
| 169 | + } | |
| 127 | 170 | |
| 128 | - function checkRepoDocument($oDocument) { | |
| 129 | - global $aRepoDocumentProblems; | |
| 130 | - $aDCVs = KTDocumentContentVersion::getByDocument($oDocument); | |
| 131 | - foreach ($aDCVs as $oDCV) { | |
| 132 | - $sDocumentPath = $oDCV->getStoragePath(); | |
| 133 | - $sFullPath = sprintf('%s/%s', $this->fsPath, $sDocumentPath); | |
| 134 | - if (!is_file($sFullPath)) { | |
| 135 | - $this->aRepoDocumentProblems[] = array( | |
| 136 | - 'document' => $oDocument, | |
| 137 | - 'content' => $oDCV, | |
| 138 | - 'path' => $sDocumentPath, | |
| 139 | - 'doclink' => KTBrowseUtil::getUrlForDocument($oDocument), | |
| 140 | - ); | |
| 171 | + $expectedHash = $row['md5hash']; | |
| 172 | + $currentHash = md5_file($tmpPath); | |
| 173 | + if ($expectedHash != $currentHash) | |
| 174 | + { | |
| 175 | + $this->error("Hash does not match. Expected: {$expectedHash} Current: {$currentHash}"); | |
| 176 | + continue; | |
| 141 | 177 | } |
| 178 | + $this->progress(); | |
| 142 | 179 | } |
| 180 | + | |
| 181 | + print "{$this->nl}Done.{$this->nl}{$this->nl}"; | |
| 143 | 182 | } |
| 183 | + | |
| 144 | 184 | } |
| 145 | -$oDispatcher = new VerifyDispatcher; | |
| 146 | -$oDispatcher->do_main(); | |
| 185 | + | |
| 186 | + | |
| 187 | +$verification = new StorageVerification(); | |
| 188 | +$verification->run(); | |
| 147 | 189 | |
| 148 | 190 | ?> | ... | ... |