Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
test_dead_file_revisions.inc
1 <?php
29 {
30 
38  static $dirList = Array();
39 
46  public static function getName()
47  {
48  return 'Dead File Revisions';
49 
50  }//end getName()
51 
52 
59  public static function getDescription()
60  {
61  return 'A test to check for dead file revisions found in the data/file_repository directory, but the asset has been deleted.';
62 
63  }//end getDescription()
64 
81  private static function getAssetDirs($dir)
82  {
83  $dirs = Array();
84  if (!$dh = opendir($dir)) {
85  return FALSE;
86  }
87 
88  while (($file = readdir($dh)) !== false) {
89  if ($file == '.' || $file == '..') {
90  continue;
91  }
92  $fullpath = $dir . '/' . $file;
93  if (is_dir($fullpath)) {
94  $dirs[] = $fullpath;
95  }
96  }
97  closedir($dh);
98 
99  foreach ($dirs as $dir) {
100  $subdirs = self::getAssetDirs($dir);
101  if (empty($subdirs)) {
102  self::$dirList[] = $dir;
103  }
104  $dirs = array_merge($dirs, $subdirs);
105  }
106  return $dirs;
107  }
108 
121  private static function findAssetsToDelete($assetIdsOnly=TRUE)
122  {
123  $file_repo_dir = SQ_DATA_PATH . '/file_repository';
124  $private_dir = SQ_DATA_PATH . '/private';
125  if (empty(self::$dirList)) {
126  self::getAssetDirs($file_repo_dir);
127  }
128 
129  $dirs = self::$dirList;
130  sort($dirs);
131 
132  $assetsToDelete = Array();
133 
134  $fullPaths = Array();
135 
140  foreach ($dirs as $dir) {
141  $dir = str_replace($file_repo_dir, '', $dir);
142  if (!is_dir($private_dir . $dir)) {
143  $dir_parts = explode('/', $dir);
144  $assetid = array_pop($dir_parts);
145  if ($assetid == 'varieties') {
146  $dir = implode('/', $dir_parts);
147  $assetid = array_pop($dir_parts);
148  }
149  $assetsToDelete[$assetid] = $assetid;
150  $fullPaths[$assetid] = $dir;
151  }
152  }
153 
154  if ($assetIdsOnly) {
155  return $assetsToDelete;
156  }
157 
158  return $fullPaths;
159  }
160 
176  public static function execute(&$messages, &$errors)
177  {
178  $status = TRUE;
179  if (SQ_CONF_ROLLBACK_ENABLED) {
180  $messages[] = "Rollback is enabled, so will not check for orphaned file repository entries.\n\tThey may be required when viewing the system in rollback mode.";
181  $status = FALSE;
182  return $status;
183  }
184 
185  $assetsToDelete = self::findAssetsToDelete();
186 
187  $assetsCleanedUp = Array();
188 
189  if (empty($assetsToDelete)) {
190  $messages[] = 'There are no orphaned file repository entries.';
191  return $status;
192  }
193 
194  $messages[] = 'There are ' . sizeof($assetsToDelete) . ' orphaned file repository entries to clean up.';
195  $errors[] = 'Will clean up these asset ids: ' . implode(',', $assetsToDelete);
196 
197  $fullPaths = self::findAssetsToDelete(FALSE);
198 
199  foreach ($assetsToDelete as $assetid) {
200  try {
201  $exists = $GLOBALS['SQ_SYSTEM']->am->assetExists($assetid);
202  }
203  catch (Exception $e) {
204  $exists = true;
205  }
206 
207  if ($exists) {
208  $msg = "There is a problem with the data directories for asset $assetid\n";
209  $msg .= "\tThis asset still exists. Skipping.";
210  $messages[] = $msg;
211  unset($assetsToDelete[$assetid]);
212  unset($fullPaths[$assetid]);
213  continue;
214  }
215  $filedir = $fullPaths[$assetid];
216  $path = SQ_DATA_PATH . '/file_repository' . $filedir;
217  $file_list = list_files($path, TRUE);
218  // see if the 'varieties' exists for this asset
219  if (is_dir($path.'/varieties')) {
220  $file_list = array_merge($file_list, list_files($path.'/varieties', TRUE));
221  }
222  $bad_files = Array();
223  foreach ($file_list as $file) {
224  $ok = unlink($file);
225  if (!$ok) {
226  $bad_files[] = $file;
227  }
228  }
229  if (empty($bad_files)) {
230  if (is_dir($path.'/varieties')) {
231  rmdir($path.'/varieties');
232  }
233  rmdir($path);
234  $assetsCleanedUp[] = $assetid;
235  } else {
236  $msg = "Unable to delete the following files:\n";
237  $msg .= implode("\n\t\t", $bad_files);
238  $messages[] = $msg;
239  unset($assetsToDelete[$assetid]);
240  unset($fullPaths[$assetid]);
241  $status = FALSE;
242  }
243  }
244 
249  if (!empty($fullPaths)) {
250 
251  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('db2');
252  $db = MatrixDAL::getDb();
253  $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
254 
255  $fileIds = Array();
256 
257  foreach (array_chunk($fullPaths, 999) as $chunk) {
258  $query = "SELECT fileid FROM sq_file_vers_file WHERE path IN (";
259  foreach ($chunk as $path) {
260  $query .= MatrixDAL::quote(ltrim($path, '/')) . ",";
261  }
262  $query = rtrim($query, ',') . ')';
263 
264  $fileInfo = MatrixDAL::executeSqlAll($query);
265 
266  foreach ($fileInfo as $row => $details) {
267  $fileIds[] = MatrixDAL::quote($details['fileid']);
268  }
269  }
270 
271  foreach (array_chunk($fileIds, 999) as $chunk) {
272  $query = "DELETE FROM sq_file_vers_file WHERE fileid IN (" . implode(',', $chunk) . ")";
273  $result = MatrixDAL::executeSql($query);
274  $query = "DELETE FROM sq_file_vers_history WHERE fileid IN (" . implode(',', $chunk) . ")";
275  $result = MatrixDAL::executeSql($query);
276  }
277 
278  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
279  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
280  }
281 
282  $msg = "The following assets were cleaned up successfully:\n";
283  $msg .= "\t" . implode(',', $assetsCleanedUp);
284  $messages[] = $msg;
285 
286  return $status;
287  }
288 
300  public static function test(&$messages, &$errors)
301  {
302  $status = FALSE;
303  if (SQ_CONF_ROLLBACK_ENABLED) {
304  $messages[] = "Rollback is enabled, so will not check for orphaned file repository entries.\n\tThey may be required when viewing the system in rollback mode.";
305  return $status;
306  }
307 
308  $assetsToDelete = self::findAssetsToDelete();
309 
310  if (empty($assetsToDelete)) {
311  $messages[] = 'There are no orphaned file repository entries.';
312  $status = TRUE;
313  } else {
314  $messages[] = 'There are ' . sizeof($assetsToDelete) . ' orphaned file repository entries to clean up.';
315  $errors[] = 'Will clean up these asset ids: ' . implode(',', $assetsToDelete);
316  }
317 
318  return $status;
319 
320  }//end test()
321 
322 }//end class
323 ?>