get_parms( "base_id" , "hotfolder" , "period" , "move_archived" , "move_error" , "copy_spe" , "delfolder" , 'cold' ); $dom = new DOMDocument(); $dom->formatOutput = true; $dom->preserveWhiteSpace = false; if( $dom->loadXML($oldxml) ) { $xmlchanged = false; // foreach($parm2 as $pname=>$pvalue) foreach(array("str:base_id", "str:hotfolder", "str:period", "boo:move_archived", "boo:move_error", "boo:delfolder", 'boo:copy_spe', 'str:cold') as $pname) { $ptype = substr($pname, 0, 3); $pname = substr($pname, 4); $pvalue = $parm2[$pname]; if( $ns = $dom->getElementsByTagName($pname)->item(0) ) { // le champ existait dans le xml, on supprime son ancienne valeur (tout le contenu) while( ($n = $ns->firstChild) ) $ns->removeChild($n); } else { // le champ n'existait pas dans le xml, on le cree $ns = $dom->documentElement->appendChild($dom->createElement($pname)); } // on fixe sa valeur switch($ptype) { case "str": $ns->appendChild($dom->createTextNode($pvalue)); break; case "boo": $ns->appendChild($dom->createTextNode($pvalue ? '1':'0')); break; } $xmlchanged = true; } } return($dom->saveXML()); } // ==================================================================== // xml2graphic : must fill the graphic form (using js) from xml // ==================================================================== public function xml2graphic($xml, $form) { if( ($sxml = simplexml_load_string($xml)) ) // in fact XML IS always valid here... { // ... but we could check for safe values (ex. 0 < period < 3600) if( (int)($sxml->period) < 10 ) $sxml->period = 10; elseif( (int)($sxml->period) > 300 ) $sxml->period = 300; if( (int)($sxml->cold) < 5 ) $sxml->cold = 5; elseif( (int)($sxml->cold) > 3600 ) $sxml->cold = 3600; ?>
:



 :   

 :   

        

 

 
array("set"=>false, "values"=>array(), "usage"=>" : usage du truc") ); // ====================================================================================================== // ===== help() : text displayed if --help (optional) // ====================================================================================================== function help() { return(_("task::archive:Archiving files found into a 'hotfolder'")); } // ====================================================================================================== // ===== run() : le code d'execution de la teche proprement dite // ====================================================================================================== private $mimeTypes = array( "jpg"=>"image/jpeg", "jpeg"=>"image/jpeg", "pdf"=>"application/pdf" ); private $hotfiles = array(); // la liste de TOUS les fichiers 'chauds' (en cours d'arrivee ftp ?) private $sxTaskSettings = null; // les settings de la tache en simplexml private $connbas = null; // cnx e la base private $running = false; private $msg = ""; // copy settings to task, so it's easier to get later private $move_archived = true; // default value private $move_error = true; // default value function run() { $this->debug = false; if( ($this->sxTaskSettings = simplexml_load_string($this->taskSettings)) ) { } else { // Settings illisibles return(false); } return($this->run2()); } private function run2() { $ret = ''; $server_coll_id = null; $conn = connection::getInstance(); $base_id = (int)($this->sxTaskSettings->base_id); $sql = 'SELECT s.sbas_id, b.server_coll_id FROM bas b INNER JOIN sbas s ON s.sbas_id=b.sbas_id WHERE b.base_id="'.$base_id.'"' ; if($rs = $conn->query($sql)) { if($row = $conn->fetch_assoc($rs)) { $this->connbas = connection::getInstance($row['sbas_id']); $server_coll_id = $row["server_coll_id"]; try { $this->connbas->isok() || generalException::get('no db'); // on liste les collections disponibles $this->TColls = array(); $sql = 'SELECT coll_id FROM coll'; $rsbas = $this->connbas->query($sql); while($rowbas = $this->connbas->fetch_assoc($rsbas)) $this->TColls['c'.$rowbas['coll_id']] = $rowbas; $this->connbas->free_result($rsbas); // on lit les prefs de cette collection $sql = "SELECT uid AS maxcoll, value AS baseprefs, prefs AS collprefs FROM uids, pref, coll WHERE uids.name='COLL' AND pref.prop='structure' AND coll_id='" . $server_coll_id ."'"; $rsbas = $this->connbas->query($sql); $rowbas = $this->connbas->fetch_assoc($rsbas); $this->connbas->free_result($rsbas); $rowbas || generalException::get('no prefs for collection '.$server_coll_id); } catch(Exception $e) { print($e->getMessage()); return('tostop'); } } $conn->free_result($rs); } // ici : // conn est une connexion e application server du site // rowtask : record de la teche en cours // connbas est une connexion e la base distante // rowbas : record contenant les prefs de base et collection // on a les prefs de coll directement dans la session $this->running = true; $this->tmask = array(); // les masques de fichiers acceptes par cette tache $this->tmaskgrp = array(); $this->period = 60; $this->cold = 60; if( ($this->sxBasePrefs = simplexml_load_string($rowbas["baseprefs"])) ) { $this->sxBasePrefs["id"] = $base_id; // info utile $do_it = true; $this->period = (int)($this->sxTaskSettings->period); if($this->period <= 0 || $this->period >= 60*60) $this->period = 60; $this->cold = (int)($this->sxTaskSettings->cold); if($this->cold <= 0 || $this->cold >= 60*60) $this->cold = 60; // si on doit copier le doc dans la base, on verifie que le dossier existe $copyhd = true; $pathhd = (string)($this->sxBasePrefs->path); if($copyhd && $pathhd) { if(!is_dir($pathhd)) p4::fullmkdir($pathhd); if(!is_dir($pathhd)) { $this->log(sprintf(_('task::archive:Can\'t create or go to folder \'%s\''), $pathhd)); $this->running = false; } } // on charge les masques de fichiers if($this->sxTaskSettings->files && $this->sxTaskSettings->files->file) { foreach($this->sxTaskSettings->files->file as $ft) $this->tmask[] = array("mask"=>(string)($ft["mask"]), "caption"=>(string)($ft["caption"]), "accept"=>(string)($ft["accept"])); } if($this->sxTaskSettings->files && $this->sxTaskSettings->files->grouping) { foreach($this->sxTaskSettings->files->grouping as $ft) $this->tmaskgrp[] = array("mask"=>(string)($ft["mask"]), "caption"=>(string)($ft["caption"]),"representation"=>(string)($ft["representation"]), "accept"=>(string)($ft["accept"])); } if(count($this->tmask)==0) { // pas de masque defini : on accepte tout $this->tmask[] = array("mask"=>".*", "caption"=>"", "accept"=>""); } // ici la teche tourne tant qu'elle est active $loop = 0; while($this->running) { if(!$conn || !$conn->ping()) { $this->log(("Warning : abox connection lost, restarting in 10 min.")); sleep(60*10); $this->running = false; return(''); } if(!$this->connbas->ping()) { $this->log(("dbox connection lost, restarting in 10 min.")); sleep(60*10); $this->running = false; return(''); } $path_in = (string)($this->sxTaskSettings->hotfolder); if(!@is_dir( $path_in )) { $this->log(sprintf(('missing hotfolder \'%s\', restarting in 10 min.'), $path_in)); sleep(60*10); $this->running = false; return(''); } // printf("====================== LOOP ====================== \n"); $sql = "UPDATE task2 SET last_exec_time=NOW() WHERE task_id=" . $this->taskid ; $conn->query($sql); $sql = "SELECT * FROM task2 WHERE task_id=" . $this->taskid ; if($rs = $conn->query($sql)) { $row = $conn->fetch_assoc($rs); $conn->free_result($rs); if($row) { if($row['status'] == 'tostop') { $ret = 'stopped'; $this->running = false; } else { if( $this->sxTaskSettings = simplexml_load_string($row['settings']) ) { // copy settings to task, so it's easier to get later $this->move_archived = p4field::isyes($this->sxTaskSettings->move_archived); $this->move_error = p4field::isyes($this->sxTaskSettings->move_error); $period = (int)($this->sxTaskSettings->period); if($period <= 0 || $period >= 60*60) $period = 60; $cold = (int)($this->sxTaskSettings->cold); if($cold <= 0 || $cold >= 60*60) $cold = 60; } else { $period = 60; $cold = 60; } $duration = time(); $r = $this->archiveHotFolder($server_coll_id); if($loop > 10) $r = 'MAXLOOP'; switch($r) { case 'WAIT': $ret = 'stopped'; $this->running = false; break; case 'BAD': $ret = 'stopped'; $this->running = false; break; case 'NORECSTODO': $duration = time() - $duration; if($duration < ($period+$cold)) { $conn->close(); sleep(($period+$cold) - $duration); unset($conn); $conn = connection::getInstance(); } break; case 'MAXRECSDONE': case 'MAXMEMORY': case 'LOOP': case 'MAXLOOP': if($row['status'] == 'started') { $ret = 'torestart'; $this->running = false; } break; default: if($row['status'] == 'started') { $ret = 'stopped'; $this->running = false; } break; } } } else { $this->running = false; } } else { $this->running = false; } $loop++; } } return($ret); } function archiveHotFolder($server_coll_id) { // $this->filesToIgnore = array('.', '..', 'Thumbs.db', ''); clearstatcache(); $conn = connection::getInstance(); $path_in = p4string::delEndSlash(trim((string)($this->sxTaskSettings->hotfolder))); if(!@is_file($path_in . "/.phrasea.xml")) { $this->log(sprintf(('NO .phrasea.xml AT ROOT v2 \'%s\' !'), $path_in)); return('WAIT'); } $path_archived = $path_error = null; if($this->move_archived) { $path_archived = $path_in . '_archived'; @mkdir($path_archived, 0755, true); if(!file_exists($path_archived)) { $this->log(sprintf(('Can\'t create folder \'%s\' !'), $path_archived)); return('BAD'); } } if($this->move_error) { $path_error = $path_in . '_error'; @mkdir($path_error, 0755, true); if(!file_exists($path_error)) { $this->log(sprintf(('archive:Can\'t create folder \'%s\' !'), $path_error)); return('BAD'); } } $dom = new DOMDocument(); $dom->formatOutput = true; $root = $dom->appendChild($dom->createElement('root')); $this->movedFiles = 0; $this->archivedFiles = 0; $this->path_in = $path_in; $nnew = $this->listFilesPhase1($dom, $root, $path_in, $server_coll_id); if($this->debug) $this->log("=========== listFilesPhase1 ========== (returned ".$nnew.")\n" . $dom->saveXML()); $cold = (int)($this->sxTaskSettings->cold); if($cold <= 0 || $cold >= 60*60) $cold = 60; $sql = "SELECT status FROM task2 WHERE task_id=" . $this->taskid ; while($cold > 0) { if($rs = $conn->query($sql)) { $row = $conn->fetch_assoc($rs); $conn->free_result($rs); if($row && $row['status'] == 'tostop') return('NORECSTODO'); } sleep(2); $cold -= 2; } $this->listFilesPhase2($dom, $root, $path_in); if($this->debug) $this->log("=========== listFilesPhase2 ========== : \n" . $dom->saveXML()); $this->makePairs($dom, $root, $path_in, $path_archived, $path_error); if($this->debug) $this->log("=========== makePairs ========== : \n" . $dom->saveXML()); $r = $this->removeBadGroups($dom, $root, $path_in, $path_archived, $path_error); if($this->debug) $this->log("=========== removeBadGroups ========== (returned ".($r?'true':'false').") : \n" . $dom->saveXML()); $this->archive($dom, $root, $path_in, $path_archived, $path_error); if($this->debug) $this->log("=========== archive ========== : \n" . $dom->saveXML()); $this->bubbleResults($dom, $root, $path_in); if($this->debug) $this->log("=========== bubbleResults ========== : \n" . $dom->saveXML()); $r = $this->moveFiles($dom, $root, $path_in, $path_archived, $path_error); if($this->debug) $this->log("=========== moveFiles ========== (returned ".($r?'true':'false').") : \n" . $dom->saveXML()); if($this->movedFiles) { // something happened : a least one file has moved return('MAXRECSDONE'); } elseif(memory_get_usage()>>20 > 15) { return('MAXMEMORY'); } else { return('NORECSTODO'); } //print($dom->saveXML()); // unset($dom); // die(); } function isIgnoredFile($f) { return($f=='.' || $f=='..' || $f=='Thumbs.db' || $f=='par-SYSTEM' || substr($f, 0, 10)=='.com.apple'); // return(substr($f,0,1)=='.' || $f=='Thumbs.db' || $f=='par-SYSTEM'); } /** * check if the file matches any mask, and flag the 'caption' file if found * * @param unknown_type $dom * @param unknown_type $node * @param unknown_type $path * @param unknown_type $grp_rid */ function checkMatch($dom, $node) { $file = $node->getAttribute('name'); foreach($this->tmask as $mask) { $preg_mask = '/' . $mask['mask'] . '/'; if(preg_match($preg_mask, $file)) { if($mask['caption']) { // caption in a linked file ? $captionFileName = @preg_replace($preg_mask, $mask['caption'], $file); $xpath = new DOMXPath($dom); $dnl = $xpath->query('./file[@name="'.$captionFileName.'"]', $node->parentNode); if($dnl->length == 1) { // the caption file exists $node->setAttribute('match', $captionFileName); $dnl->item(0)->setAttribute('match', '*'); } else { // the caption file is missing $node->setAttribute('match', '?'); } } else { // self-described $node->setAttribute('match', '.'); } // first match is ok break; } } } /** * Phase 1 : * list every file, all 'hot' * read .phrasea.xml files * * @param unknown_type $dom * @param unknown_type $node * @param unknown_type $path * @param unknown_type $server_coll_id */ function listFilesPhase1($dom, $node, $path, $server_coll_id) { // $this->traceRam(); $nnew = 0; try { $listFolder = new CListFolder($path, GV_ArchiveSorted); if( ($sxDotPhrasea = @simplexml_load_file($path.'/.phrasea.xml')) ) { // on gere le magicfile if( ($magicfile = trim((string)($sxDotPhrasea->magicfile))) != '') { $magicmethod = strtoupper($sxDotPhrasea->magicfile['method']); if($magicmethod=='LOCK' && file_exists($path.'/'.$magicfile)) return; elseif($magicmethod=='UNLOCK' && !file_exists($path.'/'.$magicfile)) return; } // on gere le changement de collection if( ($new_cid = $sxDotPhrasea['collection']) != '' ) { //printf("new_cid=%s\n", $new_cid); //var_dump($this->TColls); if(isset($this->TColls['c'.$new_cid])) { $server_coll_id = $new_cid; } else { $this->log(sprintf(('Unknown coll_id (%1$d) in "%2$s"'), (int)$new_cid, $path.'/.phrasea.xml')); $server_coll_id = -1; } } $node->setAttribute('pxml', '1'); } $iloop = 0; while( ($file = $listFolder->read()) !== NULL ) { if($this->isIgnoredFile($file)) continue; if( ($iloop++ % 100) == 0) usleep(1000); if(is_dir($path.'/'.$file)) { $n = $node->appendChild($dom->createElement('file')); $n->setAttribute('isdir', '1'); $n->setAttribute('name', $file); $nnew += $this->listFilesPhase1($dom, $n, $path.'/'.$file, $server_coll_id); } else { $n = $node->appendChild($dom->createElement('file')); $n->setAttribute('name', $file); $stat = stat($path.'/'.$file); foreach(array("size", "ctime", "mtime") as $k) $n->setAttribute($k, $stat[$k]); $nnew++; } $n->setAttribute('cid', $server_coll_id); $n->setAttribute('temperature', 'hot'); } } catch(Exception $e) { } return($nnew); } /** * Phase 2 : * list again and flag dead files as 'cold' * * @param unknown_type $dom * @param unknown_type $node * @param unknown_type $path */ function listFilesPhase2($dom, $node, $path, $depth=0) { static $iloop = 0; if($depth == 0) $iloop = 0; $nnew = 0; try { $listFolder = new CListFolder($path, GV_ArchiveSorted); $xp = new DOMXPath($dom); while( ($file = $listFolder->read()) !== NULL ) { if($this->isIgnoredFile($file)) continue; if( ($iloop++ % 100) == 0) usleep(500); $dnl = @$xp->query('./file[@name="'.$file.'"]', $node); // if(!$dnl) // printf("%s \n", './file[@name="'.$file.'"]'); if($dnl && $dnl->length == 0) { if(is_dir($path.'/'.$file)) { $n = $node->appendChild($dom->createElement('file')); $n->setAttribute('isdir', '1'); $n->setAttribute('name', $file); $nnew += $this->listFilesPhase2($dom, $n, $path.'/'.$file, $depth+1); } else { $n = $node->appendChild($dom->createElement('file')); $n->setAttribute('name', $file); // $stat = stat($path.'/'.$file); // foreach(array("size", "ctime", "mtime") as $k) // $n->setAttribute($k, $stat[$k]); $nnew++; } // $n->setAttribute('cid', $server_coll_id); // $n->setAttribute('temperature', 'hot'); $this->setBranchHot($dom, $n); } elseif($dnl && $dnl->length == 1) { $dnl->item(0)->setAttribute('temperature', 'cold'); // $dnl->item(0)->removeAttribute('hot'); if(is_dir($path.'/'.$file)) { $this->listFilesPhase2($dom, $dnl->item(0), $path.'/'.$file, $depth+1); } else { $stat = stat($path.'/'.$file); foreach(array("size", "ctime", "mtime") as $k) { if($dnl->item(0)->getAttribute($k) != $stat[$k]) { $this->setBranchHot($dom, $dnl->item(0)); break; } } } } } } catch(Exception $e) { } } /** * makePairs : * flag files to be archived (make pairs with linked caption when needed) * flag grp folders and their linked files (caption, representation) * declare uncomplete grp as error * * @param unknown_type $dom * @param unknown_type $node * @param unknown_type $path */ function makePairs($dom, $node, $path, $path_archived, $path_error, $inGrp=false, $depth=0) { static $iloop = 0; if($depth == 0) $iloop = 0; if($depth==0 && ($node->getAttribute('temperature')=='hot' || $node->getAttribute('cid')=='-1')) return; $xpath = new DOMXPath($dom); // useful for($n=$node->firstChild; $n; $n=$n->nextSibling) { if( ($iloop++ % 100) == 0) usleep(1000); // make xml lighter (free ram) foreach(array("size", "ctime", "mtime") as $k) $n->removeAttribute($k); if($n->getAttribute('temperature')=='hot' || $n->getAttribute('cid')=='-1') continue; $name = $n->getAttribute('name'); if($n->getAttribute('isdir')=='1') { if( ($grpSettings = $this->getGrpSettings($name)) !== FALSE) // get 'caption', 'representation' { // this is a grp folder, we check it $dnl = $xpath->query('./file[@name=".grouping.xml"]', $n); if($dnl->length == 1) { // this group is old (don't care about any linked files), just flag it $n->setAttribute('grp', 'tocomplete'); $dnl->item(0)->setAttribute('match', '*'); // recurse only if group is ok $this->makePairs($dom, $n, $path.'/'.$name, true, $depth+1); } else { // this group in new (to be created) // do we need one (or both) linked file ? (caption or representation) $err = false; $flink = array('caption'=>null, 'representation'=>null); foreach($flink as $linkName=>$v) { if(isset($grpSettings[$linkName]) && $grpSettings[$linkName]!='') { // we need this linked file, calc his real name $f = preg_replace('/'.$grpSettings['mask'].'/i', $grpSettings[$linkName], $name); $dnl = $xpath->query('./file[@name="'.$f.'"]', $node); if($dnl->length == 1) { $flink[$linkName] = $dnl->item(0); // it's here } else { $this->log(sprintf(('missing linked file \'%1$s\' to group \'%2$s\''), $f, $name)); $err = true; // missing -> error } } } if(!$err) { // the group is ok, flag it ... $n->setAttribute('grp', 'tocreate'); // ... as the existing linked file(s) ... foreach($flink as $linkName=>$v) { if($v) // this linked file exists { // $v->setAttribute('grp', '1'); $v->setAttribute('match', '*'); $n->setAttribute('grp_'.$linkName, $v->getAttribute('name')); } } // recurse only if group is ok $this->makePairs($dom, $n, $path.'/'.$name , $path_archived.'/'.$name , $path_error.'/'.$name , true, $depth+1); } else { // something is missing, the whole group goes error, ... $n->setAttribute('grp', 'todelete'); $this->setAllChildren($dom, $n, array('error'=>'1')); // bubble to the top for($nn=$n; $nn && $nn->nodeType==XML_ELEMENT_NODE; $nn=$nn->parentNode) $nn->setAttribute('error', '1'); // ... as the existing linked file(s) ... foreach($flink as $linkName=>$v) { if($v) // this linked file exists, it goes error also $v->setAttribute('error', '1'); } } } } else { // not a grp folder, recurse $this->makePairs($dom, $n, $path.'/'.$name , $path_archived.'/'.$name , $path_error.'/'.$name , $inGrp, $depth+1); } } else { // this is a file if(!$n->getAttribute('match')) // because match can be set before { if($name == '.phrasea.xml') $n->setAttribute('match', '*'); // special file(s) always ok else $this->checkMatch($dom, $n); } } } // scan again for unmatched files for($n=$node->firstChild; $n; $n=$n->nextSibling) { if(!$n->getAttribute('isdir')=='1' && !$n->getAttribute('match')) { // still no match, now it's an error (bubble to the top) for($nn=$n; $nn && $nn->nodeType==XML_ELEMENT_NODE; $nn=$nn->parentNode) $nn->setAttribute('error', '1'); } } } /** * removeBadGroups : * move files to archived or error dir * * @param unknown_type $dom * @param unknown_type $node * @param unknown_type $path * @param unknown_type $path_archived * @param unknown_type $path_error */ function removeBadGroups($dom, $node, $path, $path_archived, $path_error, $depth=0) { static $iloop=0; if($depth == 0) $iloop = 0; $ret = false; if($depth==0 && $node->getAttribute('temperature')=='hot') // if root of hotfolder if hot, die... return($ret); //printf("%s : \n", __LINE__); $nodesToDel = array(); for($n=$node->firstChild; $n; $n=$n->nextSibling) { if( ($iloop++ % 20) == 0) usleep(1000); if($n->getAttribute('temperature')=='hot') // do not move hotfiles continue; //printf("%s : \n", __LINE__); $name = $n->getAttribute('name'); //printf("----------------\n file %s : \n ", $path.'/'.$name); //$fp = fopen('php://stdin', 'r'); //fgets($fp); //fclose($fp); if($n->getAttribute('isdir')) { // a dir // if($n->getAttribute('error') && $this->move_error) // { // @mkdir($path_error . '/' . $name); // } $ret |= $this->removeBadGroups($dom, $n, $path.'/'.$name , $path_archived.'/'.$name , $path_error.'/'.$name , $depth+1); if($n->getAttribute('grp')=='todelete') { $nodesToDel[] = $n; @unlink($path.'/'.$name); } } else { // a file if($n->getAttribute('error')) { // printf("%s : \n", __LINE__); if($this->move_error) { $rootpath = p4string::delEndSlash(trim((string)($this->sxTaskSettings->hotfolder))); $subpath = substr($path, strlen($rootpath)); $this->log(sprintf(('copy \'%s\' to \'error\''), $subpath.'/'.$name)); @mkdir($path_error, 0755, true); @copy($path.'/'.$name, $path_error.'/'.$name); } $nodesToDel[] = $n; @unlink($path.'/'.$name); $this->movedFiles++; } } } foreach($nodesToDel as $n) $n->parentNode->removeChild($n); } /** * archive : * archive files * do special work on grp folders * * @param unknown_type $dom * @param unknown_type $node * @param unknown_type $path */ function archive($dom, $node, $path, $path_archived, $path_error, $depth=0) { static $iloop = 0; if($depth == 0) $iloop = 0; if($node->getAttribute('temperature')=='hot') return; $nodesToDel = array(); for($n=$node->firstChild; $n; $n=$n->nextSibling) { if( ($iloop++ % 20) == 0) usleep(1000); if($n->getAttribute('temperature')=='hot') continue; if($n->getAttribute('cid')=='-1') { $n->setAttribute('error', '1'); continue; } if($n->getAttribute('isdir')=='1') { if($n->getAttribute('grp')) { // a grp folder : special work $this->ArchiveGrp($dom, $n, $path, $path_archived, $path_error, $nodesToDel); } else { // ...normal subfolder : recurse $name = $n->getAttribute('name'); $this->archive($dom, $n, $path.'/'.$name , $path_archived.'/'.$name , $path_error.'/'.$name , $depth+1); } } else { // a file $this->archiveFile($dom, $n, $path, $path_archived, $path_error, $nodesToDel, 0); // 0 = no grp } } // printf("========== %s === %s ====== \n", __LINE__, var_export($nodesToDel, true)); foreach($nodesToDel as $n) $n->parentNode->removeChild($n); // at the end of recursion, restore the magic file (create or delete it) if( ($magicfile = $node->getAttribute('magicfile')) != '') { $magicmethod = $node->getAttribute('magicmethod'); if($magicmethod=='LOCK') file_put_contents($path.'/'.$magicfile, ''); elseif($magicmethod=='UNLOCK') unlink($path.'/'.$magicfile); } } /** * bubbleResults : * bubble result attributes ('keep', 'archived', 'error') up to top, * to help creation of result folders and cleaning of the hotfolder * * @param unknown_type $dom * @param unknown_type $node * @param unknown_type $path * @return unknown */ function bubbleResults($dom, $node, $path, $depth=0) { static $iloop=0; if($depth == 0) $iloop = 0; if($node->getAttribute('temperature')=='hot') return; $ret = 0; for($n=$node->firstChild; $n; $n=$n->nextSibling) { if( ($iloop++ % 20) == 0) usleep(1000); if($n->getAttribute('name') == '.phrasea.xml' || $n->getAttribute('name') == '.grouping.xml') { // special files stay in place AND are copied into 'archived' $n->setAttribute('keep', '1'); if(p4field::isyes($this->sxTaskSettings->copy_spe)) $n->setAttribute('archived', '1'); } // else // { // if(!$n->getAttribute('isdir') && ($n->getAttribute('temperature') == 'cold' && !$n->getAttribute('archived'))) // { // $n->setAttribute('error', '1'); // } // } if($n->getAttribute('keep') == '1') $ret |= 1; if($n->getAttribute('archived') == '1') $ret |= 2; if($n->getAttribute('error') == '1') $ret |= 4; if($n->getAttribute('isdir') == '1') $ret |= $this->bubbleResults($dom, $n, $path.'/'.$n->getAttribute('name'), $depth+1); } if($ret & 1) $node->setAttribute('keep', '1'); if($ret & 2) $node->setAttribute('archived', '1'); if($ret & 4) $node->setAttribute('error', '1'); return($ret); } /** * Phase 5 : * move files to archived or error dir * * @param unknown_type $dom * @param unknown_type $node * @param unknown_type $path * @param unknown_type $path_archived * @param unknown_type $path_error */ function moveFiles($dom, $node, $path, $path_archived, $path_error, $depth=0) { static $iloop=0; if($depth == 0) $iloop = 0; $ret = false; if($depth==0 && $node->getAttribute('temperature')=='hot') // if root of hotfolder if hot, die... return($ret); //printf("%s : \n", __LINE__); $nodesToDel = array(); for($n=$node->firstChild; $n; $n=$n->nextSibling) { if( ($iloop++ % 20) == 0) usleep(1000); if($n->getAttribute('temperature')=='hot') // do not move hotfiles continue; //printf("%s : \n", __LINE__); $name = $n->getAttribute('name'); //printf("----------------\n file %s : \n ", $path.'/'.$name); //$fp = fopen('php://stdin', 'r'); //fgets($fp); //fclose($fp); if($n->getAttribute('isdir')) { // printf("%s : ('%s', '%s')\n", __LINE__, $path_archived, $path_error); // $new_path_archived = $new_path_error = null; // if($n->getAttribute('archived') && $this->move_archived) // { // @mkdir($new_path_archived = ($path_archived . '/' . $name)); // if(!is_dir($new_path_archived)) // { // $rootpath = p4string::delEndSlash(trim((string)($this->sxTaskSettings->hotfolder))); // $subpath = substr($new_path_archived, strlen($rootpath)); // // $this->log("error subfolder '".$subpath."' does not exits"); // } // } // // if($n->getAttribute('error') && $this->move_error) // { // @mkdir($new_path_error = ($path_error . '/' . $name)); // if(!is_dir($new_path_error)) // { // $rootpath = p4string::delEndSlash(trim((string)($this->sxTaskSettings->hotfolder))); // $subpath = substr($new_path_error, strlen($rootpath)); // // $this->log("error subfolder '".$subpath."' does not exists"); // } // } $ret |= $this->moveFiles($dom, $n, $path.'/'.$name , $path_archived.'/'.$name , $path_error.'/'.$name , $depth+1); if(!$n->firstChild) $nodesToDel[] = $n; // ----- JY 20100318 : DO NOT DELETE EMPTY FOLDERS ANYMORE, AS THEY MAY DISAPEAR TOO SOON ----- // if(!$n->getAttribute('keep')) // @rmdir($path.'/'.$name); // -------------------------------------------------------------------------------------------- } else { //printf("%s : \n", __LINE__); $rootpath = p4string::delEndSlash(trim((string)($this->sxTaskSettings->hotfolder))); $subpath = substr($path, strlen($rootpath)); if($n->getAttribute('archived') && $this->move_archived) { $this->log(sprintf(('copy \'%s\' to \'archived\''), $subpath.'/'.$name)); @mkdir($path_archived, 0755, true); @copy($path.'/'.$name, $path_archived.'/'.$name); if(!$n->getAttribute('keep')) // do not count copy of special files as a real event { $nodesToDel[] = $n; $ret = true; } } if($n->getAttribute('error') && $this->move_error) { // printf("%s : \n", __LINE__); $this->log(sprintf(('copy \'%s\' to \'error\''), $subpath.'/'.$name)); @mkdir($path_error, 0755, true); @copy($path.'/'.$name, $path_error.'/'.$name); if(!$n->getAttribute('keep')) // do not count copy of special files as a real event { $nodesToDel[] = $n; $ret = true; } //printf("-> copy to %s \n", $path_error.'/'.$name); } if(!$n->getAttribute('keep')) { //printf("-> unlink %s \n", $path.'/'.$name); $this->log(sprintf(('delete \'%s\''), $subpath.'/'.$name)); if(@unlink($path.'/'.$name)) { // $n->parentNode->removeChild($n); $this->movedFiles++; } else { $this->log(sprintf(("Warning : can't delete '%s' from hotfolder, task is stopped"), $subpath.'/'.$name)); } } } } foreach($nodesToDel as $n) $n->parentNode->removeChild($n); return($ret); } function setBranchHot($dom, $node) { for($n=$node; $n; $n=$n->parentNode) { if($n->nodeType == XML_ELEMENT_NODE) { $n->setAttribute('temperature', 'hot'); if($n->hasAttribute('pxml')) break; } } } /** * special work for a grp folder : * create the grp if needed * archive files * * @param unknown_type $dom * @param unknown_type $node * @param unknown_type $parentPath */ function archiveGrp($dom, $node, $path, $path_archived, $path_error, &$nodesToDel) { $xpath = new DOMXPath($dom); // useful $node->setAttribute('keep', '1'); // grp folders stay in place $grpFolder = $node->getAttribute('name'); $groupingFile = $path.'/'.$grpFolder.'/.grouping.xml'; if($node->getAttribute('grp') == 'tocreate') { $representationFileName = null; $representationFileNode = null; $captionFileName = null; $captionFileNode = null; $cid = $node->getAttribute('cid'); $genericdoc = null; $rootpath = p4string::delEndSlash(trim((string)($this->sxTaskSettings->hotfolder))); $subpath = substr($path, strlen($rootpath)); $this->log(sprintf(('created story \'%s\''), $subpath.'/'.$grpFolder)); // if the .grp does not have a representative doc, let's use a generic file if(!($rep = $node->getAttribute('grp_representation'))) { copy(p4string::addEndSlash(GV_RootPath).'www/skins/icons/substitution/regroup_doc.png', $genericdoc=($path.'/group.jpg')); $representationFileName = 'group.jpg'; $this->log((' (no representation file)')); } else { $dnl = $xpath->query('./file[@name="'.$rep.'"]', $node->parentNode); $representationFileNode = $dnl->item(0); $representationFileName = $rep; $node->removeAttribute('grp_representation'); $this->log(sprintf(('representation from \'%s\''), $representationFileName)); } if( ($cap = $node->getAttribute('grp_caption')) ) { $dnl = $xpath->query('./file[@name="'.$cap.'"]', $node->parentNode); $captionFileNode = $dnl->item(0); $captionFileName = $cap; $node->removeAttribute('grp_caption'); $this->log(sprintf(('caption from \'%s\''), $captionFileName)); } $rid = $this->connbas->getId("RECORD", 1); $mimeExt = giveMimeExt($path.'/'.$representationFileName); $propfile = array( 'recordid' => $rid, 'extension' => $mimeExt['ext'], 'mime' => $mimeExt['mime'], 'size' => sprintf('%u', filesize($path.'/'.$representationFileName)), 'subpath' => $subpath, 'parentdirectory' => '', 'hotfolderfile' => $path.'/'.$representationFileName, 'hotfoldercaptionfile' => $path.'/'.$captionFileName, 'pathhd' => '', 'file' => '', 'originalname' => $representationFileName, 'inbase' => 0, 'type' => giveMeDocType($mimeExt['mime']) ); $pi = pathinfo($subpath); $propfile['parentdirectory'] = $pi["basename"]; $meta = get_xml($this->sxBasePrefs, $propfile); $stat0 = $stat1= "0"; if($this->sxBasePrefs->status) $stat0 = (string)($this->sxBasePrefs->status); if($this->sxTaskSettings->status) $stat1 = (string)($this->sxTaskSettings->status); if(!$stat0) $stat0 = '0'; if(!$stat1) $stat1 = '0'; // ... flag the record as 'to reindex' (status-bits 0 and 1 to 0) AND UNLOCK IT (status-bit 2 to 1) // ... and flag it for subdef creation (jeton bit 0 to 1) $fl = 'coll_id, record_id, parent_record_id, status, jeton, moddate, credate, xml, type, sha256'; $vl = $cid . ', ' .$rid . ', ' .$rid . ', (((' . $stat0 . ' | ' . $stat1 . ') & ~0x0F) | 0x0C), '.JETON_MAKE_SUBDEF.', NOW(), NOW(), \'' . $this->connbas->escape_string($meta['xml']->saveXML()) . '\', \'' . $this->connbas->escape_string($propfile['type']) . '\', \''.hash_file('sha256',$propfile["hotfolderfile"]).'\''; $sql = 'INSERT INTO record ('.$fl.') VALUES ('.$vl.')'; $this->connbas->query($sql); $copyhd = true; $documentisok = false; $this->log(sprintf((' (recordId %s)'), $rid)); if($copyhd) { // archiving with copy into base $pathhd = trim((string)($this->sxBasePrefs->path)); $pathhd = p4string::addEndSlash(p4::dispatch($pathhd)); if(!is_dir($pathhd)) p4::fullmkdir($pathhd); $newname = $rid . "_document.".$propfile["extension"]; if(copy($propfile["hotfolderfile"], $pathhd . $newname)) { $propfile['pathhd'] = $pathhd; $propfile['file'] = $newname; $propfile['inbase'] = 1; $fl = 'record_id'; $vl = $rid; $fl .= ', name'; $vl .= ", 'document'"; $fl .= ', path'; $vl .= ", '" . $this->connbas->escape_string($propfile['pathhd']) . "'"; $fl .= ', file'; $vl .= ", '" . $this->connbas->escape_string($propfile['file']) . "'"; $fl .= ', baseurl'; $vl .= ", ''"; $fl .= ', inbase'; $vl .= ", '" . $propfile['inbase'] . "'"; if(isset($propfile['width'])) { $fl .= ', width'; $vl .= ", '" . $this->connbas->escape_string($propfile['width']) . "'"; } if(isset($propfile['height'])) { $fl .= ', height'; $vl .= ", '" . $this->connbas->escape_string($propfile['height']) . "'"; } $fl .= ', mime'; $vl .= ", '" . $this->connbas->escape_string($propfile['mime']) . "'"; $fl .= ', size'; $vl .= ", '" . $this->connbas->escape_string($propfile['size']) . "'"; $fl .= ', dispatched'; $vl .= ", '1'"; $sql = "INSERT INTO subdef (".$fl.") VALUES (".$vl.")"; $this->connbas->query($sql); } $this->archivedFiles++; } else { // archiving 'in place' } if($genericdoc) unlink($genericdoc); // ok here // , create a .grouping.xml in the hotfolder file_put_contents($groupingFile, ''); $n = $node->appendChild($dom->createElement('file')); $n->setAttribute('name', '.grouping.xml'); $n->setAttribute('temperature', 'cold'); $n->setAttribute('grp', '1'); // $n->setAttribute('archived', '1'); $n->setAttribute('match', '*'); if($this->move_archived) { $this->log(sprintf(('copy \'%s\' to \'archived\''), $subpath.'/'.$grpFolder.'/.grouping.xml')); @mkdir($path_archived.'/'.$grpFolder, 0755, true); @copy($path.'/'.$grpFolder.'/.grouping.xml', $path_archived.'/'.$grpFolder.'/.grouping.xml'); } // if($captionFileNode) { $captionFileNode->setAttribute('archived', '1'); if($this->move_archived) { $this->log(sprintf(('copy \'%s\' to \'archived\''), $subpath.'/'.$captionFileName)); if(!is_dir($path_archived)) @mkdir($path_archived, 0755, true); @copy($path.'/'.$captionFileName, $path_archived.'/'.$captionFileName); } @unlink($path.'/'.$captionFileName); $nodesToDel[] = $captionFileNode; $this->movedFiles++; } if($representationFileNode) { $representationFileNode->setAttribute('archived', '1'); if($this->move_archived) { $this->log(sprintf(('copy \'%s\' to \'archived\''), $subpath.'/'.$representationFileName)); if(!is_dir($path_archived)) @mkdir($path_archived, 0755, true); @copy($path.'/'.$representationFileName, $path_archived.'/'.$representationFileName); } @unlink($path.'/'.$representationFileName); $nodesToDel[] = $representationFileNode; $this->movedFiles++; } // $node->setAttribute('grp', 'tocomplete'); } // here the .grouping.xml should exists if(file_exists($groupingFile)) { // a .grouping.xml must stay in place // -- don't do, done in phase4 //$xpath = new DOMXPath($dom); //$dnl = $xpath->query('./file[@name=".grouping.xml"]', $node); //if($dnl->length == 1) // $dnl->item(0)->setAttribute('keep', '1'); $sxGrouping = simplexml_load_file($groupingFile); $grp_rid = $sxGrouping['grouping']; $this->archiveFilesToGrp($dom, $node, $path.'/'.$grpFolder , $path_archived.'/'.$grpFolder , $path_error.'/'.$grpFolder , $grp_rid); } } /** * archive every files inside a grp * * @param unknown_type $dom * @param unknown_type $node * @param unknown_type $path * @param unknown_type $grp_rid */ function archiveFilesToGrp($dom, $node, $path, $path_archived, $path_error, $grp_rid) { //usleep(1000); $nodesToDel = array(); for($n=$node->firstChild; $n; $n=$n->nextSibling) { if($n->getAttribute('isdir')=='1') { // in a grp, all levels goes in the same grp $node->setAttribute('archived', '1'); // the main grp folder is 'keep'ed, but not subfolders $this->archiveFilesToGrp($dom, $n, $path.'/'.$n->getAttribute('name') , $path_archived.'/'.$n->getAttribute('name') , $path_error.'/'.$n->getAttribute('name') , $grp_rid); } else { // a file $this->archiveFile($dom, $n, $path, $path_archived, $path_error, $nodesToDel, $grp_rid); } } // printf("======== %s %s \n", __LINE__, var_export($nodesToDel, true)); foreach($nodesToDel as $n) $n->parentNode->removeChild($n); } /** * ARCHIVE FILE ! * * @param unknown_type $dom * @param unknown_type $node * @param unknown_type $path * @param unknown_type $grp_rid */ function archiveFile($dom, $node, $path, $path_archived, $path_error, &$nodesToDel, $grp_rid=0) { $match = $node->getAttribute('match'); if($match == '*') return; $file = $node->getAttribute('name'); $cid = $node->getAttribute('cid'); $captionFileNode = null; $rootpath = p4string::delEndSlash(trim((string)($this->sxTaskSettings->hotfolder))); $subpath = substr($path, strlen($rootpath)); if(!$match) { // the file does not match on any mask $this->log(sprintf(("File '%s' does not match any mask"), $subpath.'/'.$file)); $node->setAttribute('error', '1'); return; } elseif($match == '?') { // the caption file is missing $this->log(sprintf(("Caption of file '%s' is missing"), $subpath.'/'.$file)); $node->setAttribute('error', '1'); return; } elseif( ($match != '.') ) // match='.' : the file does not have a separate caption { $xpath = new DOMXPath($dom); $dnl = $xpath->query('./file[@name="'.$match.'"]', $node->parentNode); // in fact, xquery has been done in checkMatch, setting match='?' if caption does not exists... if($dnl->length == 1) { // ...so we ALWAYS come here $captionFileNode = $dnl->item(0); } else { // ...so we should NEVER come here $node->setAttribute('error', '1'); return; } } $this->archiveFileAndCaption($dom, $node, $captionFileNode, $path, $path_archived, $path_error, $grp_rid, $nodesToDel); } function archiveFileAndCaption($dom, $node, $captionFileNode, $path, $path_archived, $path_error, $grp_rid, &$nodesToDel) { $ret = false; $file = $node->getAttribute('name'); $captionFileName = $captionFileNode ? $captionFileNode->getAttribute('name') : NULL; $rootpath = p4string::delEndSlash(trim((string)($this->sxTaskSettings->hotfolder))); $subpath = substr($path, strlen($rootpath)); $this->log(sprintf(("Archiving file '%s'"), $subpath.'/'.$file)); if($captionFileName !== NULL) $this->log(sprintf(' '.(" (caption in '%s')"), $captionFileName)); if($grp_rid !== 0) $this->log(sprintf(' '.(" into GRP rid=%s"), $grp_rid)); $stat0 = $stat1= "0"; if($this->sxBasePrefs->status) $stat0 = (string)($this->sxBasePrefs->status); if($this->sxTaskSettings->status) $stat1 = (string)($this->sxTaskSettings->status); if(!$stat0) $stat0 = '0'; if(!$stat1) $stat1 = '0'; $rid = $this->connbas->getId("RECORD", 1); $mimeExt = giveMimeExt($path.'/'.$file); $propfile = array( 'recordid' => $rid, 'extension' => $mimeExt['ext'], 'mime' => $mimeExt['mime'], 'size' => sprintf('%u', filesize($path.'/'.$file)), 'subpath' => $subpath, 'parentdirectory' => '', 'hotfolderfile' => $path.'/'.$file, 'hotfoldercaptionfile' => NULL, 'pathhd' => '', 'file' => '', 'originalname' => $file, 'inbase' => 0, 'type' => giveMeDocType($mimeExt['mime']) ); if($captionFileName != $file) { $propfile['hotfoldercaptionfile'] = $path.'/'.$captionFileName; } $pi = pathinfo($subpath); $propfile['parentdirectory'] = $pi["basename"]; // var_dump($propfile); $meta = get_xml($this->sxBasePrefs, $propfile); $hexstat = ''; if($meta['status'] !== NULL) { $s = strrev($meta['status']) . str_repeat('0', 64); for($a=0; $a<4; $a++) $hexstat = substr('0000'.base_convert(strrev(substr($s, $a<<4, 16)), 2, 16), -4) . $hexstat; } else { $hexstat = '0'; } $lazaret = false; $uuid = false; if($grp_rid == 0 && $captionFileName == NULL) { $this->log(sprintf(("Checkin for lazaret"))); try { $file_uuid = new uuid($path.'/'.$file); $uuid = $file_uuid->check_uuid(); $base_id = (int)($this->sxTaskSettings->base_id); $sbas_id = phrasea::sbasFromBas($base_id); $error_file = p4file::check_file_error($path.'/'.$file, $sbas_id); $status = status::or_operation($stat0, $stat1); if($meta['status']) $status = status::or_operation($status, $meta['status']); if(($uuid !== false && !$file_uuid->is_new_in_base(phrasea::sbasFromBas($base_id))) || count($error_file) > 0) { $this->log(sprintf(("Trying to move to lazaret"))); if(lazaretFile::move_uploaded_to_lazaret($path.'/'.$file, $base_id, $file, $uuid, implode("\n",$error_file), $status)) { $this->log("File %s moved to lazaret"); $lazaret = true; $node->setAttribute('archived', '1'); $this->archivedFiles++; } } else { $this->log("No need to lazaret"); } } catch (Exception $e) { $this->log(sprintf(("Error while checking for lazaret : %s"), $e->getMessage())); } } if(!$lazaret) { $cid = $node->getAttribute('cid'); // ... flag the record as 'to reindex' (status-bits 0 and 1 to 0) AND UNLOCK IT (status-bit 2 to 1) // ... and flag it for subdef creation (jeton bit 0 to 1) $fl = 'coll_id, record_id, parent_record_id, status, jeton, moddate, credate, xml, type, sha256, uuid'; $vl = $cid . ', ' .$rid . ', ' . '0' . ', (((' . $stat0 . ' | ' . $stat1 . ' | 0x' . $hexstat . ') & ~0x0F) | 0x0C), '.JETON_READ_META_DOC_MAKE_SUBDEF.', NOW(), NOW(), \'' . $this->connbas->escape_string($meta['xml']->saveXML()) . '\', \'' . $this->connbas->escape_string($propfile['type']) . '\', \''.hash_file('sha256',$propfile["hotfolderfile"]).'\', "'.$this->connbas->escape_string($uuid).'"' ; $sql = 'INSERT INTO record ('.$fl.') VALUES ('.$vl.')'; //printf("sql:%s\n", $sql); if($this->connbas->query($sql)) { if($grp_rid !== NULL) { $this->connbas->query("INSERT INTO regroup (id, rid_parent, rid_child, dateadd, ord) VALUES (NULL, $grp_rid, $rid, NOW(), 0)"); } $copyhd = true; $documentisok = false; if($copyhd) { // archiving with copy into base $pathhd = trim((string)($this->sxBasePrefs->path)); $pathhd = p4::dispatch($pathhd); $newname = $rid . "_document.".$propfile["extension"]; if(copy($propfile["hotfolderfile"], $pathhd . $newname)) { $propfile['pathhd'] = $pathhd; $propfile['file'] = $newname; $propfile['inbase'] = 1; $fl = 'record_id'; $vl = $rid; $fl .= ', name'; $vl .= ", 'document'"; $fl .= ', path'; $vl .= ", '" . $this->connbas->escape_string($propfile['pathhd']) . "'"; $fl .= ', file'; $vl .= ", '" . $this->connbas->escape_string($propfile['file']) . "'"; $fl .= ', inbase'; $vl .= ", '" . $propfile['inbase'] . "'"; if(isset($propfile['width'])) { $fl .= ', width'; $vl .= ", '" . $this->connbas->escape_string($propfile['width']) . "'"; } if(isset($propfile['height'])) { $fl .= ', height'; $vl .= ", '" . $this->connbas->escape_string($propfile['height']) . "'"; } $fl .= ', mime'; $vl .= ", '" . $this->connbas->escape_string($propfile['mime']) . "'"; $fl .= ', size'; $vl .= ", '" . $this->connbas->escape_string($propfile['size']) . "'"; $fl .= ', dispatched'; $vl .= ", '1'"; $sql = "INSERT INTO subdef (".$fl.") VALUES (".$vl.")"; if($this->connbas->query($sql)) { $node->setAttribute('archived', '1'); if($captionFileNode) $captionFileNode->setAttribute('archived', '1'); } else { $this->log(("Error : can't insert into subdef")); $node->setAttribute('error', '1'); if($captionFileNode) $captionFileNode->setAttribute('error', '1'); } } else { $this->log(sprintf(('Error : can\'t copy from \'%1$s\' to \'%$2s\''), $propfile["hotfolderfile"], $pathhd.$newname)); $node->setAttribute('error', '1'); if($captionFileNode) $captionFileNode->setAttribute('error', '1'); } } else { // archiving 'in place' $node->setAttribute('archived', '1'); if($captionFileNode) $captionFileNode->setAttribute('archived', '1'); } $this->archivedFiles++; } else { $this->log(("Error : can't insert into record")); $node->setAttribute('error', '1'); if($captionFileNode) $captionFileNode->setAttribute('error', '1'); } } if($node->getAttribute('archived') && $this->move_archived) { $this->log(sprintf(('copy \'%s\' to \'archived\''), $subpath.'/'.$file)); @mkdir($path_archived, 0755, true); @copy($path.'/'.$file, $path_archived.'/'.$file); if($captionFileName != $file) { $this->log(sprintf(('copy \'%s\' to \'archived\''), $subpath.'/'.$captionFileName)); @copy($path.'/'.$captionFileName, $path_archived.'/'.$captionFileName); } if(!$node->getAttribute('keep')) // do not count copy of special files as a real event $ret = true; } if($node->getAttribute('error') && $this->move_error) { $this->log(sprintf(('copy \'%s\' to \'error\''), $subpath.'/'.$file)); @mkdir($path_error, 0755, true); @copy($path.'/'.$file, $path_error.'/'.$file); if($captionFileName != $file) { $this->log(sprintf(('copy \'%s\' to \'error\''), $subpath.'/'.$captionFileName)); @copy($path.'/'.$captionFileName, $path_error.'/'.$captionFileName); } if(!$node->getAttribute('keep')) // do not count copy of special files as a real event $ret = true; } if(!$node->getAttribute('keep')) { $file = $node->getAttribute('name'); @unlink($path.'/'.$file); $nodesToDel[] = $node; $this->movedFiles++; } if($captionFileNode && !$captionFileNode->getAttribute('keep')) { $file = $captionFileNode->getAttribute('name'); @unlink($path.'/'.$file); $nodesToDel[] = $captionFileNode; $this->movedFiles++; } // printf("======== %s %s \n", __LINE__, var_export($nodesToDel, true)); } /** * xml facility : * set attributes to a node and all children * * @param unknown_type $dom * @param unknown_type $node * @param unknown_type $attributes */ function setAllChildren($dom, $node, $attributes, $depth=0) { static $iloop=0; if($depth==0) $iloop = 0; foreach($attributes as $a=>$v) $node->setAttribute($a, $v); if( ($iloop++ % 100) == 0) usleep(1000); for($n=$node->firstChild; $n; $n=$n->nextSibling) $this->setAllChildren($dom, $n, $attributes, $depth+1); } function getGrpSettings($file) { $matched = FALSE; foreach($this->tmaskgrp as $maskgrp) { //$attachments = null; //$attachments["representation"] = null; //$attachments["caption"] = null; $preg_maskgrp = "/" . $maskgrp["mask"] . "/"; if(preg_match($preg_maskgrp, $file)) { $matched = $maskgrp; } if($matched) break; } return($matched); } } class CListFolder { private $list; function __construct($path, $sorted = false) { $this->list = array(); if($hdir = opendir($path)) { while(false !== ($file = readdir($hdir))) $this->list[] = $file; closedir($hdir); if($sorted) natcasesort($this->list); } } function __destruct() { unset($this->list); } function read() { return(array_shift($this->list)); } }