Core  3.2
PHP API documentation
 All Data Structures Namespaces Files Functions Variables Pages
renameVaultKeys.php
Go to the documentation of this file.
1 <?php
2 /*
3  * @author Anakeen
4  * @package FDL
5 */
6 /*
7  * @var Action $action
8  */
9 
10 $usage = new ApiUsage();
11 $usage->setDefinitionText("Set Vault Big Keys");
12 $force = $usage->addHiddenParameter("force", "No Verify");
13 $dryRun = $usage->addEmptyParameter("dry-run", "Only verify");
14 $vaultid = $usage->addOptionalParameter("vaultid", "restrict to single Vault id", "", 0);
15 $stop = $usage->addEmptyParameter("stop-on-error", "Stop on first error");
16 $verbose = $usage->addEmptyParameter("verbose", "Verbose vault analysis");
17 
18 $usage->verify();
19 
20 ini_set("memory_limit", -1);
21 
23 $r->setVerbose($verbose);
24 $r->setStop($stop);
25 if (!$force) {
26  $r->verifyIndexes();
27 }
28 $r->run($dryRun, $vaultid);
29 
31 {
32  protected $attrIds = array();
33  protected $vaultFile = null;
34  protected $logFile = null;
35  protected $dryRun = false;
36  protected $verbose = false;
37  protected $stop = false;
38  private $randKey = 0;
39  private $minIndex = 0;
40  private $maxIndex = 0;
41  const timeWindow = 10;
42  const timeWindowFactor = 100;
43  /**
44  * @param boolean $verbose
45  */
46  public function setVerbose($verbose)
47  {
48  $this->verbose = $verbose;
49  }
50  /**
51  * @param boolean $stop
52  */
53  public function setStop($stop)
54  {
55  $this->stop = $stop;
56  }
57  public function __construct()
58  {
59  $this->vaultFile = new VaultDiskStorage();
60  $this->logFile = sprintf("%s/.renameVaultKeys.log", DEFAULT_PUBDIR);
61  if (PHP_INT_SIZE >= 8) {
62  $this->minIndex = 1 << 31;
63  } else {
64  $this->minIndex = $this->getSequenceNextVal('seq_id_vaultdiskstorage');
65  }
66  $this->maxIndex = PHP_INT_MAX;
67  }
68  public function getSequenceNextVal($seqName)
69  {
70  simpleQuery('', sprintf("SELECT nextval(%s)", pg_escape_literal($seqName)) , $res, true, true, true);
71  return $res;
72  }
73  public function run($dryRun, $vaultid)
74  {
75  $this->dryRun = $dryRun;
76  $this->recover();
77 
78  $sql = <<<'SQL'
79 PREPARE update_docvaultindex_vaultid (bigint, bigint) AS UPDATE docvaultindex SET vaultid = $1 WHERE vaultid = $2;
80 SQL;
81  simpleQuery('', $sql, $res, false, false, true);
82 
83  $sql = <<<'SQL'
84 PREPARE update_vaultdiskstorage_id_file (bigint, bigint) AS UPDATE vaultdiskstorage SET id_file = $1 where id_file = $2;
85 SQL;
86  simpleQuery('', $sql, $res, false, false, true);
87 
88  $sql = <<<'SQL'
89 PREPARE update_vaultdiskstorage_teng_id_file (bigint, bigint) AS UPDATE vaultdiskstorage SET teng_id_file = $1 where teng_id_file = $2;
90 SQL;
91  simpleQuery('', $sql, $res, false, false, true);
92 
93  $sql = <<<'SQL'
94 SELECT
95  docvaultindex.vaultid,
96  count(docvaultindex.vaultid) AS n,
97  array_agg(docfrom.id) AS docids,
98  array_agg(docfrom.fromid) AS fromids
99 FROM
100  docvaultindex,
101  docfrom
102 WHERE
103  docfrom.id = docvaultindex.docid AND
104  docvaultindex.vaultid < %s %s
105 GROUP BY docvaultindex.vaultid
106 ORDER BY docvaultindex.vaultid
107 SQL;
108 
109  $sql = sprintf($sql, pg_escape_literal($this->minIndex) , empty($vaultid) ? "" : sprintf("and docvaultindex.vaultid = %s", pg_escape_literal($vaultid)));
110 
111  $this->verbose("Retrieve vault file to reindex...");
112  simpleQuery("", $sql, $vaultIndexes);
113  $count = count($vaultIndexes);
114  $this->verbose(sprintf("%d to update.\n", $count));
115 
116  if ($this->dryRun) {
117  $this->vaultFile->savePoint("DRY");
118  }
119  $kt = 0;
120  $ticTime = [];
121  foreach ($vaultIndexes as $ki => $vaultIndex) {
122  $docids = explode(",", substr($vaultIndex["docids"], 1, -1));
123  $fromids = array_unique(explode(",", substr($vaultIndex["fromids"], 1, -1)));
124  $vaultId = $vaultIndex["vaultid"];
125 
126  $fileInfo = \Dcp\VaultManager::getFileInfo($vaultId);
127  if (!$fileInfo) {
128  //throw new \Dcp\Exception(sprintf("Unknow file ref \"%s\" in vault database", $vaultId));
129  $this->verbose(sprintf("Unknow file ref \"%s\" in vault database", $vaultId));
130  continue;
131  }
132  if ($fileInfo->public_access === "t") {
133  continue;
134  }
135 
136  try {
137 
138  $this->vaultFile->savePoint("VAULTKEYS");
139 
140  $newId = $this->getNewVaultId();
141  $this->verbose("%d/%d) Updating vault key %s -> %s\n", $ki + 1, $count, $vaultId, $newId);
142  foreach ($fromids as $fromid) {
143  if ($fromid > 0) {
144  $this->verbose("\tUpdating documents #%s\n", implode(",", $docids));
145  $this->updateDocData($vaultId, $newId, $fromid, $docids);
146  } else {
147  $this->updateFamilyData($vaultId, $newId, $docids);
148  }
149  }
150  $this->updateVaultData($newId, $fileInfo);
151 
152  $this->vaultFile->commitPoint("VAULTKEYS");
153  $this->logVault(" ", " ");
154  if ($ki % self::timeWindow === 0) {
155  $now = microtime(true);
156  $ticTime[($kt++) % self::timeWindowFactor] = $now;
157  $tenTime = $now - min($ticTime);
158  $remaid = ($count - $ki) / self::timeWindow * $tenTime / count($ticTime);
159 
160  $this->verboseColor("Time Left: %-20s (%d/%d)", $this->humanDelay($remaid) , $ki + 1, $count);
161  }
162  }
163  catch(Exception $e) {
164  $this->vaultFile->rollbackPoint("VAULTKEYS");
165  if ($this->stop) {
166  throw $e;
167  } else {
168  $color = "\033" . '[01;31m';
169  $nocolor = "\033" . '[0m';
170  fprintf(STDERR, $e->getMessage() . "\n");
171  print ($color . "Error:" . $e->getMessage() . $nocolor . "\n");
172  }
173  }
174  }
175  if ($this->dryRun) {
176  $this->vaultFile->rollbackPoint("DRY");
177  }
178  print "\n";
179  }
180 
181  protected function humanDelay($delay)
182  {
183  if ($delay > 3600) {
184  $sDelay = sprintf("%dh %02dmin", $delay / 3600, ($delay % 3600) / 60);
185  } elseif ($delay > 60) {
186  $sDelay = sprintf("%02dmin %02ds", $delay / 60, $delay % 60);
187  } else {
188  $sDelay = sprintf("%02ds", $delay);
189  }
190  return $sDelay;
191  }
192  /**
193  * Check Vault integrity indexes
194  * @throws \Dcp\Exception
195  */
196  public function verifyIndexes()
197  {
198  $vaultAnalyzer = new \Dcp\Vault\VaultAnalyzer();
199  $report = array();
200  $vaultAnalyzer->setVerbose($this->verbose);
201  $consistent = $vaultAnalyzer->checkDocVaultIndex($report);
202  if (!$consistent) {
203  throw new \Dcp\Exception("Vault index is corrupted. Use \"refreshVaultIndex\" wsh script to verify/repair index");
204  }
205  }
206  /**
207  * Complete rename vault identifier : rename real file name
208  * @param int $newId new vault identifier
209  * @param VaultFileInfo $fileInfo
210  * @throws \Dcp\Db\Exception
211  * @throws \Dcp\Exception
212  */
213  protected function updateVaultData($newId, VaultFileInfo $fileInfo)
214  {
215  $vaultId = $fileInfo->id_file;
216  $currentFileName = $fileInfo->path;
217  $currentDirName = dirname($currentFileName);
218  $currentBaseName = basename($currentFileName);
219  if (!preg_match('/^(?P<vid>\d+)(?P<extension>\..*)$/', $currentBaseName, $m)) {
220  throw new \Dcp\Exception(sprintf("Malformed filename '%s'.", $currentFileName));
221  }
222  if ($vaultId !== $m['vid']) {
223  throw new \Dcp\Exception(sprintf("VID mismatch between filename '%s' and vid '%s'.", $currentFileName, $m['vid']));
224  }
225  $newBaseName = sprintf("%s%s", $newId, $m['extension']);
226  $newFileName = $currentDirName . DIRECTORY_SEPARATOR . $newBaseName;
227  $this->verbose("\tmv %s %s \n", $currentFileName, $newFileName);
228 
229  if (!$this->dryRun) {
230  $sql = sprintf("EXECUTE update_docvaultindex_vaultid(%s, %s)", pg_escape_literal($newId) , pg_escape_literal($vaultId));
231  simpleQuery("", $sql, $res, false, false, true);
232  $sql = sprintf("EXECUTE update_vaultdiskstorage_id_file(%s, %s)", pg_escape_literal($newId) , pg_escape_literal($vaultId));
233  simpleQuery("", $sql, $res, false, false, true);
234  $sql = sprintf("EXECUTE update_vaultdiskstorage_teng_id_file(%s, %s)", pg_escape_literal($newId) , pg_escape_literal($vaultId));
235  simpleQuery("", $sql, $res, false, false, true);
236  $this->logVault($currentFileName, $newFileName);
237  if (!rename($currentFileName, $newFileName)) {
238  throw new \Dcp\Exception("Cannot rename $currentFileName to $newFileName");
239  }
240  }
241  }
242  /**
243  * Log current file rename
244  * @param string $currentName
245  * @param string $newName
246  * @throws \Dcp\Exception
247  */
248  protected function logVault($currentName, $newName)
249  {
250  if (!$this->dryRun) {
251  if (file_put_contents($this->logFile, sprintf("%s\n%s", $currentName, $newName)) === false) {
252  throw new \Dcp\Exception(sprintf("Error writing content to transaction's log file '%s'.", $this->logFile));
253  }
254  }
255  }
256  protected function recover()
257  {
258  if ($this->dryRun) {
259  return;
260  }
261  if (is_file($this->logFile)) {
262  if (($data = file($this->logFile)) === false) {
263  throw new \Dcp\Exception(sprintf("Error reading content from transaction's log file '%s'.", $this->logFile));
264  }
265  if ($data) {
266  $newFileName = trim($data[1]);
267  $currentFileName = trim($data[0]);
268 
269  if ($newFileName && $currentFileName && !rename($newFileName, $currentFileName)) {
270  throw new \Dcp\Exception("Cannot rename $newFileName to $currentFileName");
271  }
272  }
273  }
274  }
275 
276  protected function verbose($format)
277  {
278  if ($this->verbose) {
279  call_user_func_array("printf", func_get_args());
280  }
281  }
282  protected function verboseColor($format)
283  {
284  $color = "\033" . '[1;33;40m';
285  $nocolor = "\033" . '[0m';
286 
287  $args = func_get_args();
288  if ($this->verbose) {
289 
290  $args[0] = "\t" . $color . $args[0] . $nocolor . "\n";
291  } else {
292  $color = "\033" . '[1;33m';
293  $args[0] = "\r" . $color . $args[0] . $nocolor;
294  }
295  call_user_func_array("printf", $args);
296  }
297  /**
298  * Update file family parameters
299  * @param int $vaultId current vault identifier
300  * @param int $newId new vault identifier
301  * @param int[] $docids family identifiers
302  * @throws \Dcp\Exception
303  */
304  protected function updateFamilyData($vaultId, $newId, $docids)
305  {
306 
307  $s = new SearchDoc("", -1);
308  $s->addFilter("id in (%s)", implode(",", $docids));
309  $s->setObjectReturn();
310  $dl = $s->getDocumentList();
311  /*
312  * @var DocFam $family
313  */
314  foreach ($dl as $family) {
315  $attributes = $family->getAttributes();
316  $parameters = $family->getOwnParams();
317  $defVal = $family->getOwnDefValues();
318  $needModify = false;
319  foreach ($attributes as $oattr) {
320  if (($oattr->type === "file" || $oattr->type === "image")) {
321  if ($oattr->usefor === "Q") {
322  if (!empty($parameters[$oattr->id])) {
323  $newValue = str_replace('|' . $vaultId . '|', '|' . $newId . '|', $parameters[$oattr->id]);
324  if ($newValue !== $parameters[$oattr->id]) {
325  $err = $family->setParam($oattr->id, $newValue);
326  if ($err) {
327  throw new \Dcp\Exception(sprintf("Cannot update family (%s) parameter (%s) : %s ", $family->name, $oattr->id, $err));
328  }
329  $this->verbose("Update family \"%s\" parameter \"%s\"", $family->name, $oattr->id);
330  $needModify = true;
331  }
332  }
333  }
334 
335  if (!empty($defVal[$oattr->id])) {
336  $newValue = str_replace('|' . $vaultId . '|', '|' . $newId . '|', $defVal[$oattr->id]);
337  if ($newValue !== $defVal[$oattr->id]) {
338  $err = $family->setDefValue($oattr->id, $newValue);
339  if ($err) {
340  throw new \Dcp\Exception(sprintf("Cannot update family (%s) default value (%s) : %s ", $family->name, $oattr->id, $err));
341  }
342  $this->verbose("Update family \"%s\" default value \"%s\"", $family->name, $oattr->id);
343  $needModify = true;
344  }
345  }
346  }
347  }
348 
349  if ($needModify) {
350  $err = $family->modify(false);
351  if ($err) {
352  throw new \Dcp\Exception(sprintf("Cannot update family (%s) : %s ", $family->name, $err));
353  }
354  }
355  }
356  }
357  /**
358  * Set new index for file document attributes
359  * @param int $vaultId current vault identifier
360  * @param int $newId new vault identifier
361  * @param int $fromid document's family identifier to search
362  * @param int[] $docids document identifiers to update
363  * @throws \Dcp\Exception
364  */
365  protected function updateDocData($vaultId, $newId, $fromid, $docids)
366  {
367  $attrs = $this->getFamilyFileAttrIds($fromid);
368 
369  if ($attrs) {
370  $sql = sprintf("update doc%d ", $fromid);
371  $first = true;
372  foreach ($attrs as $attr) {
373  if ($first) {
374  $sql.= " set ";
375  $first = false;
376  } else {
377  $sql.= ", ";
378  }
379  $sql.= sprintf(" %s=regexp_replace(%s, E'\\\\|%s($|\\n|[\\\\|.*])',E'|%s\\\\1','g')", pg_escape_string($attr) , pg_escape_string($attr) , $vaultId, $newId);
380  }
381 
382  $sql.= sprintf(" where id in (%s)", implode(",", $docids));
383 
384  if (!$this->dryRun) {
385  simpleQuery("", $sql);
386 
387  $sql = sprintf("EXECUTE update_docvaultindex_vaultid(%s, %s)", pg_escape_literal($newId) , pg_escape_literal($vaultId));
388  simpleQuery("", $sql);
389  }
390  }
391  }
392  /**
393  * Get file attributes for given family
394  * @param int $famId family identifier
395  * @return mixed
396  */
397  protected function getFamilyFileAttrIds($famId)
398  {
399  if (!isset($this->attrIds[$famId])) {
400  $d = new DocFam("", $famId);
401  $this->attrIds[$famId] = [];
402  $attributes = $d->getFileAttributes();
403  foreach ($attributes as $oa) {
404  $this->attrIds[$famId][] = $oa->id;
405  }
406  }
407  return $this->attrIds[$famId];
408  }
409  protected function getNewVaultId()
410  {
411  if ($this->randKey === 0) {
412  $this->randKey = 1;
413  mt_srand($this->vaultFile->getNewVaultId());
414  }
415 
416  $nogood = true;
417  $newId = 0;
418  while ($nogood) {
419  $newId = mt_rand($this->minIndex, $this->maxIndex);
420  simpleQuery("", sprintf("select true from vaultdiskstorage where id_file = %s", $newId) , $nogood, true, true);
421  }
422 
423  return $newId;
424  }
425 }
if(substr($wsh, 0, 1)!= '/') $args
updateVaultData($newId, VaultFileInfo $fileInfo)
print t $msg n
getFamilyFileAttrIds($famId)
$vaultid
getSequenceNextVal($seqName)
updateDocData($vaultId, $newId, $fromid, $docids)
$verbose
if($famId) $s
$d
Definition: dav.php:77
$vaultAnalyzer
const DEFAULT_PUBDIR
Definition: Lib.Prefix.php:28
logVault($currentName, $newName)
setVerbose($verbose)
run($dryRun, $vaultid)
static getFileInfo($idfile, $teng_name="")
print
Definition: checklist.php:49
updateFamilyData($vaultId, $newId, $docids)
simpleQuery($dbaccess, $query, &$result=array(), $singlecolumn=false, $singleresult=false, $useStrict=null)
Definition: Lib.Common.php:484
if($file) if($subject==""&&$file) if($subject=="") $err
Verify arguments for wsh programs.
$data
← centre documentaire © anakeen