Core  3.2
PHP API documentation
 All Data Structures Namespaces Files Functions Variables Pages
Class.ExportCollection.php
Go to the documentation of this file.
1 <?php
2 /*
3  * @author Anakeen
4  * @package FDL
5 */
6 
7 namespace Dcp;
9 {
10  /**
11  * @var bool Indicate if Profile must be exported also
12  */
13  protected $exportProfil = false;
14 
15  protected $exportFiles = false;
16 
17  protected $exportDocumentNumericIdentiers = false;
18 
19  const utf8Encoding = "utf-8";
20  const latinEncoding = "iso8859-15";
21  protected $outputFileEncoding = self::utf8Encoding;
22 
23  protected $useUserColumnParameter = false;
24 
25  const csvRawOutputFormat = "I";
26  const csvRawOnlyDataOutputFormat = "R";
27  const csvDisplayValueOutputFormat = "F";
28  const xmlArchiveOutputFormat = "X";
29  const xmlFileOutputFormat = "Y";
30 
31  protected $outputFormat = self::csvRawOutputFormat;
32  protected $verifyAttributeAccess = false;
33 
34  protected $cvsSeparator = ";";
35  protected $cvsEnclosure = "";
36  protected $profileAccountType = ExportDocument::useAclAccountType;
37 
38  protected $outputFilePath = '';
39  /**
40  * @var string status use to show progress
41  */
42  protected $exportStatusId = '';
43  /**
44  * @var \DocCollection $collectionDocument
45  */
46  protected $collectionDocument = null;
47  /**
48  * @var \DocumentList
49  */
50  protected $documentList = null;
51  /**
52  * @var resource output file handler
53  */
54  protected $outHandler = null;
55  protected $moreDocuments = array();
56  protected $familyData = array();
57  /**
58  * If true, attribute with "I" visibility are not returned
59  * @param boolean $verifyAttributeAccess
60  */
61  public function setVerifyAttributeAccess($verifyAttributeAccess)
62  {
63  $this->verifyAttributeAccess = $verifyAttributeAccess;
64  }
65  /**
66  * @param string $cvsEnclosure
67  */
68  public function setCvsEnclosure($cvsEnclosure)
69  {
70  $this->cvsEnclosure = $cvsEnclosure;
71  }
72  /**
73  * Use document collection (folder or searcch) to export documents
74  * @see ExportCollection::setDocumentlist
75  * @param \DocCollection $collectionDocument
76  */
77  public function setCollectionDocument(\DocCollection $collectionDocument)
78  {
79  $this->collectionDocument = $collectionDocument;
80  $this->documentList = $this->collectionDocument->getDocumentList();
81  }
82  /**
83  * File to record result of export (must be writable)
84  * The file will be overwrite if exists
85  * @param string $outputFilePath
86  */
87  public function setOutputFilePath($outputFilePath)
88  {
89  $this->outputFilePath = $outputFilePath;
90  }
91  /**
92  * Set identifier key to write status
93  * @see ExportCollection::setStatus
94  * @param string $exportStatusId
95  */
96  public function setExportStatusId($exportStatusId)
97  {
98  $this->exportStatusId = $exportStatusId;
99  }
100  /**
101  * Type of acl reference when export profile
102  * @param string $profileAccountType
103  */
104  public function setProfileAccountType($profileAccountType)
105  {
106  $this->profileAccountType = $profileAccountType;
107  }
108  /**
109  * Get output file name
110  * @see ExportCollection::setOutputFilePath
111  * @return string
112  */
113  public function getOutputFilePath()
114  {
115  return $this->outputFilePath;
116  }
117  /**
118  * Set CSV separator character
119  * @param string $cvsSeparator
120  * @throws Exception
121  */
122  public function setCvsSeparator($cvsSeparator)
123  {
124  if (strlen($cvsSeparator) !== 1) {
125  throw new Exception("EXPC0016", $cvsSeparator);
126  }
127  $this->cvsSeparator = $cvsSeparator;
128  }
129  /**
130  * Only in csv, and no profil, export numeric identifier if no logical name
131  * Else identifier is not exported
132  * @param boolean $exportDocumentNumericIdentiers
133  */
134  public function setExportDocumentNumericIdentiers($exportDocumentNumericIdentiers)
135  {
136  $this->exportDocumentNumericIdentiers = $exportDocumentNumericIdentiers;
137  }
138  /**
139  * Indicate if export also attached files
140  * @param boolean $exportFiles
141  */
142  public function setExportFiles($exportFiles)
143  {
144  $this->exportFiles = $exportFiles;
145  }
146  /**
147  * Indicate if Profile data must be exported also
148  * @param boolean $exportProfil
149  */
150  public function setExportProfil($exportProfil)
151  {
152  $this->exportProfil = $exportProfil;
153  }
154  /**
155  * Set encoding format default is UTF-8
156  * @param string $outputFileEncding
157  * @throws Exception
158  */
159  public function setOutputFileEncoding($outputFileEncding)
160  {
161  $allowedFormat = array(
162  self::utf8Encoding,
163  self::latinEncoding
164  );
165  if (!in_array($outputFileEncding, $allowedFormat)) {
166  throw new Exception("EXPC0015", $outputFileEncding, implode(",", $allowedFormat));
167  }
168  $this->outputFileEncoding = $outputFileEncding;
169  }
170  /**
171  * Indicate file output format
172  * @param string $outputFormat
173  * @throws Exception
174  */
175  public function setOutputFormat($outputFormat)
176  {
177  $allowedFormat = array(
178  self::csvRawOutputFormat,
179  self::csvRawOnlyDataOutputFormat,
180  self::csvDisplayValueOutputFormat,
181  self::xmlArchiveOutputFormat,
182  self::xmlFileOutputFormat
183  );
184  if (!in_array($outputFormat, $allowedFormat)) {
185  throw new Exception("EXPC0001", $outputFormat, implode(",", $allowedFormat));
186  }
187  $this->outputFormat = $outputFormat;
188  }
189  /**
190  * Only for csv mode. Set true if need to export only column set by applicative parameter "FREEDOM_EXPORTCOLS"
191  * @param boolean $useUserColumnParameter
192  */
193  public function setUseUserColumnParameter($useUserColumnParameter)
194  {
195  $this->useUserColumnParameter = $useUserColumnParameter;
196  }
197  /**
198  * Export Document LIst
199  * @see ExportCollection::setDocumentlist
200  * @throws Exception
201  */
202  public function export()
203  {
204  if (empty($this->outputFilePath)) {
205  throw new Exception("EXPC0002");
206  }
207  if (file_exists($this->outputFilePath) && !is_writable($this->outputFilePath)) {
208  throw new Exception("EXPC0003", $this->outputFilePath);
209  }
210  if ($this->documentList === null) {
211  throw new Exception("EXPC0004");
212  }
213 
214  switch ($this->outputFormat) {
215  case self::csvRawOutputFormat:
216  case self::csvRawOnlyDataOutputFormat:
217  case self::csvDisplayValueOutputFormat:
218  $this->exportCsv();
219  break;
220 
221  case self::xmlArchiveOutputFormat:
222  case self::xmlFileOutputFormat:
223  $this->exportCollectionXml();
224  break;
225  }
226  }
227  /**
228  * Set documentList to export
229  * @param \DocumentList $documentList
230  */
231  public function setDocumentlist(\DocumentList $documentList)
232  {
233  $this->documentList = $documentList;
234  }
235  /**
236  * Export to csv file
237  * @throws Exception
238  */
239  protected function exportCsv()
240  {
241  $dl = $this->documentList;
242  $exportDoc = new \Dcp\ExportDocument();
243  $exportDoc->setCsvEnclosure($this->cvsEnclosure);
244  $exportDoc->setCsvSeparator($this->cvsSeparator);
245  $exportDoc->setExportAccountType($this->profileAccountType);
246  $exportDoc->setVerifyAttributeAccess($this->verifyAttributeAccess);
247  $outDir = '';
248  if ($this->exportFiles) {
249  $outDir = tempnam(getTmpDir() , 'exportFolder');
250  if (is_file($outDir)) {
251  unlink($outDir);
252  }
253  mkdir($outDir);
254  $fdlcsv = $outDir . "/fdl.csv";
255  $this->outHandler = fopen($fdlcsv, "w");
256  if (!$this->outHandler) {
257  throw new Exception("EXPC0012", $fdlcsv);
258  }
259  } else {
260  $this->outHandler = fopen($this->outputFilePath, "w");
261  if (!$this->outHandler) {
262  throw new Exception("EXPC0005", $this->outputFilePath);
263  }
264  }
265 
266  $c = 0;
267  $rc = count($dl);
268  if ($this->exportProfil) {
269  foreach ($dl as $doc) {
270  $this->recordStatus(sprintf(_("Record documents %d/%d") , $c, $rc));
271  if ($doc->doctype === "C") {
272  /**
273  * @var \DocFam $doc
274  */
275  $c++;
276  if ($c % 20 == 0) {
277  $this->recordStatus(sprintf(_("Record documents %d/%d") , $c, $rc));
278  }
279  $this->csvFamilyExport($doc);
280  }
281  }
282  $this->writeFamilies();
283  }
284  $fileInfos = array();
285  foreach ($dl as $doc) {
286 
287  if ($doc->doctype !== "C") {
288  $c++;
289  if ($c % 20 == 0) {
290 
291  $this->recordStatus(sprintf(_("Record documents %d/%d") , $c, $rc));
292  }
293  $exportDoc->csvExport($doc, $fileInfos, $this->outHandler, $this->exportProfil, $this->exportFiles, $this->exportDocumentNumericIdentiers, ($this->outputFileEncoding === self::utf8Encoding) , !$this->useUserColumnParameter, $this->outputFormat);
294  }
295  }
296  fclose($this->outHandler);
297 
298  if ($this->exportFiles) {
299  $this->zipFiles($outDir, $fileInfos);
300  }
301  }
302  /**
303  * Write message to session var. Used by interfaces to see progress
304  * @param string $msg
305  * @param bool $endStatus
306  */
307  public function recordStatus($msg, $endStatus = false)
308  {
309  if ($this->exportStatusId) {
310  global $action;
311  $warnings = array();
312  if ($endStatus) {
313  $warnings = $action->parent->getWarningMsg();
314  if (count($warnings) > 0) {
315  array_unshift($warnings, _("Export:Warnings"));
316  }
317 
318  $action->parent->clearWarningMsg();
319  }
320  $action->register($this->exportStatusId, array(
321  "status" => $msg,
322  "warnings" => $warnings,
323  "end" => $endStatus
324  ));
325  }
326  }
327  /**
328  * Record document relative to family
329  * @param string $documentId
330  */
331  protected function addDocumentToExport($documentId)
332  {
333  $this->moreDocuments[$documentId] = true;
334  }
335  /**
336  * Record family data which are write by writeFamilies
337  * @see ExportCollection::writeFamilies
338  * @param \DocFam $family
339  */
340  protected function csvFamilyExport(\DocFam $family)
341  {
342 
343  $wname = "";
344  $cvname = "";
345  $cpname = "";
346  $fpname = "";
347 
348  $tmoredoc = array();
350  if ($family->profid != $family->id) {
351  $fp = getTDoc($dbaccess, $family->profid);
352  $tmoredoc[$fp["id"]] = "famprof";
353  $this->addDocumentToExport($fp["id"]);
354  if ($fp["name"] != "") $fpname = $fp["name"];
355  else $fpname = $fp["id"];
356  } else {
357  }
358  if ($family->cprofid) {
359  $cp = getTDoc($dbaccess, $family->cprofid);
360  if ($cp["name"] != "") $cpname = $cp["name"];
361  else $cpname = $cp["id"];
362  $tmoredoc[$cp["id"]] = "cprofid";
363  $this->addDocumentToExport($cp["id"]);
364  }
365  if ($family->ccvid > 0) {
366  $cv = getTDoc($dbaccess, $family->ccvid);
367  if ($cv["name"] != "") $cvname = $cv["name"];
368  else $cvname = $cv["id"];
369  $tmskid = $family->rawValueToArray($cv["cv_mskid"]);
370 
371  foreach ($tmskid as $kmsk => $imsk) {
372  if ($imsk != "") {
373  $msk = getTDoc($dbaccess, $imsk);
374  if ($msk) {
375  $tmoredoc[$msk["id"]] = "mask";
376  $this->addDocumentToExport($msk["id"]);
377  }
378  }
379  }
380 
381  $tmoredoc[$cv["id"]] = "cv";
382  $this->addDocumentToExport($cv["id"]);
383  }
384 
385  if ($family->wid > 0) {
386  $wdoc = \new_doc($dbaccess, $family->wid);
387  if ($wdoc->name != "") $wname = $wdoc->name;
388  else $wname = $wdoc->id;
389  $tattr = $wdoc->getAttributes();
390  foreach ($tattr as $ka => $oa) {
391  if ($oa->type == "docid") {
392  $tdid = $wdoc->getMultipleRawValues($ka);
393  foreach ($tdid as $did) {
394  if ($did != "") {
395  $m = getTDoc($dbaccess, $did);
396  if ($m) {
397  if ($m["doctype"] !== "C") {
398  $tmoredoc[$m["initid"]] = "wrel";
399  $this->addDocumentToExport($m["initid"]);
400 
401  if (!empty($m["cv_mskid"])) {
402  $tmskid = $family->rawValueToArray($m["cv_mskid"]);
403  foreach ($tmskid as $kmsk => $imsk) {
404  if ($imsk != "") {
405  $msk = getTDoc($dbaccess, $imsk);
406  if ($msk) {
407  $tmoredoc[$msk["id"]] = "wmask";
408  $this->addDocumentToExport($msk["initid"]);
409  }
410  }
411  }
412  }
413  if (!empty($m["tm_tmail"])) {
414  $tmskid = $family->rawValueToArray(str_replace('<BR>', "\n", $m["tm_tmail"]));
415  foreach ($tmskid as $kmsk => $imsk) {
416  if ($imsk != "") {
417  $msk = getTDoc($dbaccess, $imsk);
418  if ($msk) {
419  $tmoredoc[$msk["id"]] = "tmask";
420  $this->addDocumentToExport($msk["initid"]);
421  }
422  }
423  }
424  }
425  }
426  }
427  }
428  }
429  }
430  }
431  $tmoredoc[$family->wid] = "wid";
432  $this->addDocumentToExport($family->wid);
433  }
434 
435  if ($cvname || $wname || $cpname || $fpname) {
436  $this->familyData[$family->id][] = array(
437  "BEGIN",
438  "",
439  "",
440  "",
441  "",
442  $family->name
443  );
444 
445  if ($fpname) {
446  $this->familyData[$family->id][] = array(
447  "PROFID",
448  $fpname
449  );
450  }
451  if ($cvname) {
452  $this->familyData[$family->id][] = array(
453  "CVID",
454  $cvname
455  );
456  }
457  if ($wname) {
458  $this->familyData[$family->id][] = array(
459  "WID",
460  $wname
461  );
462  }
463  if ($family->cprofid) {
464  $this->familyData[$family->id][] = array(
465  "CPROFID",
466  $cpname
467  );
468  }
469  $this->familyData[$family->id][] = array(
470  "END"
471  );
472  }
473  }
474  /**
475  * write family data
476  */
477  protected function writeFamilies()
478  {
479 
480  $exportDoc = new \Dcp\ExportDocument();
481  $exportDoc->setCsvEnclosure($this->cvsEnclosure);
482  $exportDoc->setCsvSeparator($this->cvsSeparator);
483 
484  $more = new \DocumentList();
485  $more->addDocumentIdentifiers(array_keys($this->moreDocuments));
486  $searchDl = $more->getSearchDocument();
487  $searchDl->setOrder("fromid, name, id");
488  foreach ($more as $adoc) {
489 
490  $exportDoc->csvExport($adoc, $fileInfos, $this->outHandler, false, $this->exportFiles, $this->exportDocumentNumericIdentiers, ($this->outputFileEncoding === self::utf8Encoding) , !$this->useUserColumnParameter, $this->outputFormat);
491  }
492  foreach ($more as $adoc) {
493 
494  $exportDoc->exportProfil($this->outHandler, $adoc->id);
495  }
496 
497  foreach ($this->familyData as $famid => $aRow) {
498  $family = \new_doc("", $famid);
499  if ($family->profid == $family->id) {
500  $exportDoc->exportProfil($this->outHandler, $family->id);
501  }
502  }
503 
504  foreach ($this->familyData as $famid => $aRow) {
505 
506  foreach ($aRow as $data) \Dcp\WriteCsv::fput($this->outHandler, $data);
507  }
508  }
509  protected function zipFiles($directory, array $infos)
510  {
511  // Copy file from vault
512  foreach ($infos as $info) {
513  $source = $info["path"];
514  $ddir = $directory . '/' . $info["ldir"];
515  if (!is_dir($ddir)) mkdir($ddir);
516  $dest = $ddir . '/' . $info["fname"];
517  if (!copy($source, $dest)) {
518  throw new Exception("EXPC0014", $source, $dest);
519  }
520  }
521 
522  $zipfile = $this->outputFilePath . ".zip";
523  $cmd = sprintf("cd %s && zip -r %s -- * > /dev/null && mv %s %s", escapeshellarg($directory) , escapeshellarg($zipfile) , escapeshellarg($zipfile) , escapeshellarg($this->outputFilePath));
524  system($cmd, $ret);
525  if (!is_file($this->outputFilePath)) {
526 
527  throw new Exception("EXPC0012", $this->outputFilePath);
528  }
529  }
530  protected function exportCollectionXml()
531  {
532  $dl = $this->documentList;
533 
534  $foutdir = uniqid(getTmpDir() . "/exportxml");
535  if (!mkdir($foutdir)) {
536  throw new Exception("EXPC0006", $foutdir);
537  }
538 
539  VerifyAttributeAccess::clearCache();
540 
541  $exd = new \Dcp\ExportXmlDocument();
542 
543  $exd->setExportFiles($this->exportFiles);
544  $exd->setExportDocumentNumericIdentiers($this->exportDocumentNumericIdentiers);
545  $exd->setStructureAttributes(true);
546  $exd->setIncludeSchemaReference(true);
547  $exd->setVerifyAttributeAccess($this->verifyAttributeAccess);
548 
549  $c = 0;
550  $rc = count($dl);
551  /**
552  * @var \Doc $doc
553  */
554  foreach ($dl as $doc) {
555  $c++;
556  if ($c % 20 == 0) {
557  $this->recordStatus(sprintf(_("Record documents %d/%d") , $c, $rc));
558  }
559 
560  $ftitle = $this->cleanFileName($doc->getTitle());
561  $suffix = sprintf("{%d}.xml", $doc->id);
562  $maxBytesLen = MAX_FILENAME_LEN - strlen($suffix);
563  $fname = sprintf("%s/%s%s", $foutdir, mb_strcut($ftitle, 0, $maxBytesLen, 'UTF-8') , $suffix);
564 
565  $exd->setDocument($doc);
566  $exd->writeTo($fname);
567  }
568 
569  if ($this->outputFormat === self::xmlFileOutputFormat) {
570  $this->catXml($foutdir);
571  } elseif ($this->outputFormat === self::xmlArchiveOutputFormat) {
572  $this->zipXml($foutdir);
573  }
574  system(sprintf("rm -fr %s", escapeshellarg($foutdir)));
575  }
576  /**
577  * Replace special character for a file name
578  * @param string $fileName
579  * @return string
580  */
581  protected static function cleanFileName($fileName)
582  {
583  return str_replace(array(
584  '/',
585  '\\',
586  '?',
587  '*',
588  "'",
589  ':',
590  " "
591  ) , array(
592  '-',
593  '-',
594  '-',
595  '-',
596  '-',
597  '_'
598  ) , $fileName);
599  }
600  /**
601  * zip Xml files included in directory
602  * @param string $directory
603  * @throws Exception
604  */
605  protected function zipXml($directory)
606  {
607 
608  $zipfile = $this->outputFilePath . ".zip";
609  $cmd = sprintf("cd %s && zip -r %s -- * > /dev/null && mv %s %s", escapeshellarg($directory) , escapeshellarg($zipfile) , escapeshellarg($zipfile) , escapeshellarg($this->outputFilePath));
610 
611  system($cmd, $ret);
612  if (!is_file($this->outputFilePath)) {
613 
614  throw new Exception("EXPC0012", $this->outputFilePath);
615  }
616  }
617  /**
618  * concatenate Xml files included in directory into single XML file
619  * @param string $directory
620  * @throws Exception
621  */
622  protected function catXml($directory)
623  {
624 
625  $fout = fopen($this->outputFilePath, "w");
626  if (!$fout) {
627  throw new Exception("EXPC0005", $this->outputFilePath);
628  }
629  $xml_head = <<<EOF
630 <?xml version="1.0" encoding="UTF-8"?>
631 <documents date="%s" author="%s" name="%s">
632 
633 EOF;
634  if ($this->collectionDocument) {
635  $exportname = $this->collectionDocument->getTitle();
636  } else {
637  $exportname = sprintf("Custom '\"export");
638  }
639  $xml_head = sprintf($xml_head, htmlspecialchars(strftime("%FT%T")) , htmlspecialchars(\Account::getDisplayName(getCurrentUser()->id) , ENT_QUOTES) , htmlspecialchars($exportname, ENT_QUOTES));
640 
641  $ret = fwrite($fout, $xml_head);
642  if ($ret === false) {
643  throw new Exception("EXPC0005", $this->outputFilePath);
644  }
645  fflush($fout);
646  /* chdir into dir containing the XML files
647  * and concatenate them into the output file
648  */
649  $cwd = getcwd();
650  $ret = chdir($directory);
651  if ($ret === false) {
652  // exportExit($action, sprintf("%s (Error chdir to '%s')", _("Xml file cannot be created") , htmlspecialchars($foutdir)));
653  throw new Exception("EXPC0008", $this->outputFilePath);
654  }
655 
656  if (count($this->documentList) > 0) {
657  $cmd = sprintf("cat -- *xml | grep -v '<?xml version=\"1.0\" encoding=\"UTF-8\"?>' >> %s", escapeshellarg($this->outputFilePath));
658  system($cmd, $ret);
659  }
660 
661  $ret = chdir($cwd);
662  if ($ret === false) {
663  // exportExit($action, sprintf("%s (Error chdir to '%s')", _("Xml file cannot be created") , htmlspecialchars($cwd)));
664  throw new Exception("EXPC0009", $cwd);
665  }
666  /* Print XML footer */
667  $ret = fseek($fout, 0, SEEK_END);
668  if ($ret === - 1) {
669  //exportExit($action, sprintf("%s (Error fseek '%s')", _("Xml file cannot be created") , htmlspecialchars($xmlfile)));
670  throw new Exception("EXPC0010", $this->outputFilePath);
671  }
672 
673  $xml_footer = "</documents>";
674  $ret = fwrite($fout, $xml_footer);
675  if ($ret === - 1) {
676  throw new Exception("EXPC0011", $this->outputFilePath);
677  }
678  fclose($fout);
679  }
680 }
$dest
Definition: resizeimg.php:231
setVerifyAttributeAccess($verifyAttributeAccess)
setExportStatusId($exportStatusId)
getTDoc($dbaccess, $id, $sqlfilters=array(), $result=array())
global $action
setProfileAccountType($profileAccountType)
const MAX_FILENAME_LEN
Definition: Lib.Prefix.php:30
csvFamilyExport(\DocFam $family)
print $fam getTitle() $fam name
static rawValueToArray($v)
Definition: Class.Doc.php:6228
Exception class use exceptionCode to identifiy correctly exception.
Definition: exceptions.php:19
$ret
setOutputFileEncoding($outputFileEncding)
static cleanFileName($fileName)
recordStatus($msg, $endStatus=false)
recordStatus(Action &$action, $exportId, $msg, $endStatus=false)
Definition: exportfld.php:246
foreach($argv as $arg) $cmd
setDocumentlist(\DocumentList $documentList)
setExportDocumentNumericIdentiers($exportDocumentNumericIdentiers)
setUseUserColumnParameter($useUserColumnParameter)
zipFiles($directory, array $infos)
static getDisplayName($uid)
setCollectionDocument(\DocCollection $collectionDocument)
getTmpDir($def= '/tmp')
Definition: Lib.Common.php:150
getCurrentUser()
Definition: Lib.Common.php:250
getDbAccess()
Definition: Lib.Common.php:368
if($_REQUEST['submitted']) else $cwd
Definition: test.php:66
$dbaccess
Definition: checkVault.php:17
$info
Definition: geticon.php:30
static fput($handler, array $data)
Definition: WriteCsv.php:22
setOutputFilePath($outputFilePath)
class use to search documents
$data
← centre documentaire © anakeen