Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
hipo_job_tool_export_files.inc
1 <?php
17 require_once SQ_SYSTEM_ROOT.'/core/hipo/hipo_job.inc';
18 
33 {
34 
35 
41  function __construct($code_name='')
42  {
43  $this->uses_trans = FALSE;
44  parent::__construct($code_name);
45  $GLOBALS['SQ_SYSTEM']->lm->includePackageStrings('cms');
46 
47  }//end constructor
48 
49 
59  function getCodeName()
60  {
61  return parent::getCodeName().'-'.$this->_running_vars['root_node'].'-'.$this->_running_vars['save_name'];
62 
63  }//end getCodeName()
64 
65 
72  function getHipoName()
73  {
74  return translate('cms_hipo_name_export_files');
75 
76  }//end getHipoName()
77 
78 
86  function getInitialStepData()
87  {
88  return Array(
89  Array(
90  'name' => translate('cms_hipo_exporting_files'),
91  'function_call' => Array(
92  'process_function' => 'processExport',
93  ),
94  'running_mode' => 'server',
95  'auto_step' => TRUE,
96  'percent_done' => 0,
97  'complete' => FALSE,
98  'message' => '',
99  'allow_cancel' => TRUE,
100  ),
101  );
102 
103  }//end getInitialStepData()
104 
105 
112  function freestyle()
113  {
114  while (!empty($this->_running_vars['todo_asset_users'])) {
115  if (!$this->processExport($this->_steps[0], get_class($this))) {
116  return FALSE;
117  }
118  }
119  return TRUE;
120 
121  }//end freestyle()
122 
123 
130  function prepare()
131  {
132  // add root_nodes into the 'todo' array
133  $i = 0;
134  $current_root_node = Array();
135 
136  // Get the root nodes
137  foreach ($this->_running_vars['root_node'] as $each_node_key => $each_node) {
138  foreach ($each_node as $node_key => $node_value) {
139  if ($node_key == 'assetid') {
140  $current_root_node[$each_node_key] = $node_value;
141  }//end if
142  }//end foreach
143  }//end foreach
144 
145  foreach ($current_root_node as $current_node) {
146  $this->_running_vars['todo_asset_users'][$i]['root_node'] = $current_node;
147  $this->_running_vars['todo_asset_users'][$i]['save_name'] = $this->_running_vars['save_name'];
148  $this->_running_vars['todo_asset_users'][$i]['save_location'] = $this->_running_vars['save_location'];
149  $this->_running_vars['todo_asset_users'][$i]['keep_structure'] = $this->_running_vars['keep_structure'];
150  $i++;
151  }//end foreach
152  $this->_running_vars['done_asset_users'] = Array();
153  return parent::prepare();
154 
155  }//end prepare()
156 
157 
167  function processExport(&$step_data, $prefix)
168  {
169  if (!empty($this->_running_vars['todo_asset_users'])) {
170 
171  // export files
172  $index = array_shift(array_keys($this->_running_vars['todo_asset_users']));
173  if (isset($this->_running_vars['todo_asset_users'][$index]['root_node'])) {
174  $step_root_node = $this->_running_vars['todo_asset_users'][$index]['root_node'];
175  } else {
176  return FALSE;
177  }
178  $root_node = $GLOBALS['SQ_SYSTEM']->am->getAsset($step_root_node);
179  $save_name = $this->_running_vars['todo_asset_users'][$index]['save_name'];
180  $save_location = $this->_running_vars['todo_asset_users'][$index]['save_location'];
181  $structure = $this->_running_vars['todo_asset_users'][$index]['keep_structure'];
182 
183  // Get the name ready
184  $filename = $save_name;
185  if (!preg_match('/(\.tar\.gz|\.tgz|\.tar)$/i', $filename)) {
186  $filename = $filename.'.tar.gz';
187  }
188 
189  // Process the node
190  $result_node = $this->processExportNode($step_root_node, $filename, $save_location, $structure);
191  if (!$result_node) {
192  trigger_error("Could not process root node: ".$root_node->id);
193  return FALSE;
194  } else {
195  unset($this->_running_vars['todo_asset_users'][$index]);
196  }//end if
197 
198  }//end if not empty todo
199 
200  // update progress
201  if (empty($this->_running_vars['todo_asset_users'])) {
202  $step_data['percent_done'] = 100;
203  $step_data['complete'] = TRUE;
204  } else {
205  $total = count($this->_running_vars['todo_asset_users']) + count($this->_running_vars['done_asset_users']);
206  $step_data['percent_done'] =(count($this->_running_vars['done_asset_users']) / $total) * 100;
207  $step_data['complete'] = FALSE;
208  }
209 
210  return TRUE;
211 
212  }//end processExport()
213 
214 
226  function processExportNode($root_node, $save_name, $save_location, $keep_structure=TRUE)
227  {
228  // Change this save location to the path that you want the files in
229  // Apache User *MUST* have read AND write access to that directory
230  $allowed_filetypes = Array(
231  'folder',
232  'file',
233  );
234 
235  $export_date = date('hisdmY');
236  $structure = $keep_structure;
237  $files = Array();
238  $depth = 0;
239 
240  // Gather a list of all the files to do
241  $files = $this->_getFiles($root_node, $allowed_filetypes, $depth);
242 
243  $tmpdir = mkdir(SQ_TEMP_PATH.'/export-'.$export_date, 0777);
244  if (!$tmpdir) {
245  trigger_localised_error('CMS0105', E_USER_NOTICE);
246  return FALSE;
247  }
248 
249  // Process the list
250  $filelist = Array();
251 
252  // Replace '/' characters in filenames by '_'
253  foreach($files as $key => $value) {
254  $filename = $value['name'];
255  $file_path = $value['path'];
256 
257  if (strpos($filename, '/') !== FALSE) {
258  $value['name'] = str_replace('/' ,'_', $filename);
259  $value['path'] = substr($file_path, 0, strlen($file_path) - strlen($filename)).$value['name'];
260 
261  $files[$key] = $value;
262  }
263  }
264 
265  $files_count = count($files);
266 
267  // Fix asset's name that are in same tree level with same name to prevent duplicate filename error
268  for($file_index = 1; $file_index <= $files_count; $file_index++) {
269  $file_val = $files[$file_index];
270 
271  $recheck_dups = FALSE;
272  for($file_index_check = 1; $file_index_check <= $files_count; $file_index_check++) {
273  if ($file_index == $file_index_check) {
274  continue;
275  }
276  $file_val_check = $files[$file_index_check];
277 
278  if ($file_val['root'] == $file_val_check['root'] && $file_val['name'] == $file_val_check['name']) {
279  // Append asset's webpath to the asset's name make the file name unique
280  $file_val_check['name'] .= '_'.$file_val_check['webpath'];
281  $file_val_check['path'] .= '_'.$file_val_check['webpath'];
282 
283  $files[$file_index_check] = $file_val_check;
284 
285  // Need to check for duplicates all again to see if this new name is conflicting with others previously checked
286  $recheck_dups = TRUE;
287  }
288  }
289 
290  if ($recheck_dups) {
291  $file_index = 1;
292  }
293  }
294 
295  foreach ($files as $key => $value) {
296 
297  // Build file list
298  $path_to = '';
299  if ($structure) {
300  $path_to = $this->_findPath($files, $value, $path_to);
301  $path_to = $path_to.'/';
302  } else {
303  $path_to = '/';
304  }
305  $filetmp = SQ_TEMP_PATH.'/export-'.$export_date.$path_to.$value['name'];
306 
307  if ($structure && $value['root'] == 0) {
308  // We only need the root files and folders here, because Archive Tar handles the structure
309  $filelist[] = '.'.$path_to.$value['name'];
310  } else if (!$structure) {
311  // Here, if there is no structure, we need all files
312  $filelist[] = './'.$value['name'];
313  }
314  // Open to the tmp directory
315  if (isset($value['path']) && !empty($value['path']) && !$value['dir']) {
316  $to_tmp = copy($value['path'], $filetmp);
317  if (!$to_tmp) {
318  trigger_localised_error('CMS0105', E_USER_NOTICE);
319  trigger_error($filetmp);
320  return FALSE;
321  }//end if
322  } else {
323  $mkdir = mkdir($filetmp, 0777);
324  if (!$mkdir) {
325  trigger_localised_error('CMS0105', E_USER_NOTICE);
326  trigger_error($filetmp);
327  return FALSE;
328  }//end if
329  }//end if
330  }//end foreach
331 
332  // Get the current dir
333  $cwd = getcwd();
334 
335  // Change to the TEMP dir
336  chdir(SQ_TEMP_PATH.'/export-'.$export_date);
337 
338  require_once 'Archive/Tar.php';
339 
340  $tar_ball = new Archive_Tar($save_location.'/'.$save_name, 'gz');
341  $result = $tar_ball->add($filelist);
342  if (PEAR::isError($result)) {
343  trigger_localised_error('CMS0105', E_USER_NOTICE);
344  return FALSE;
345  }
346 
347  // Change back
348  chdir($cwd);
349 
350  // Cleanup
351  $cleanup = TRUE;
352  $cleanup = $this->_cleanup(SQ_TEMP_PATH.'/export-'.$export_date);
353  if (!$cleanup) {
354  trigger_localised_error('CMS0106', E_USER_NOTICE);
355  }
356  return TRUE;
357 
358  }//end processExportNode()
359 
360 
371  function _findPath($list, $file, $path='')
372  {
373  // Error checking
374  if (!is_array($list) || empty($list)) {
375  return $path;
376  }
377  if (!is_array($file) || empty($file)) {
378  return $path;
379  }
380 
381  if (!isset($file['root'])) return $path;
382 
383  $tmp = $file['root'];
384 
385  if (isset($list[$tmp]['name']) && !empty($list[$tmp]['name'])) {
386  if (isset($list[$tmp]['dir']) && $list[$tmp]['dir']) {
387  $path = '/'.$list[$tmp]['name'].$path;
388  }
389  $path = $this->_findPath($list, $list[$tmp], $path);
390  }
391 
392  return $path;
393 
394  }//end _findPath()
395 
396 
407  function _getFiles($root_node, $filetypes=Array(), &$depth)
408  {
409  $files = Array();
410  $am = $GLOBALS['SQ_SYSTEM']->am;
411 
412  // Error checking
413  if (empty($root_node)) return $files;
414  if (!is_array($filetypes)) return $files;
415 
416  $child_links = $am->getLinks($root_node, SQ_SC_LINK_BACKEND_NAV, $filetypes, FALSE);
417  $files += $this->_processFiles($child_links, $filetypes, $depth);
418 
419  return $files;
420 
421  }//end _getFiles()
422 
423 
434  function _processFiles($links, $filetypes, &$depth)
435  {
436  $files = Array();
437  $am = $GLOBALS['SQ_SYSTEM']->am;
438 
439  // Error checking
440  if (!is_array($links) || empty($links)) {
441  return $files;
442  }
443  if (!is_array($filetypes)) return $files;
444 
445  $parent = $depth;
446  foreach ($links as $link) {
447  if (!isset($link['minorid'])) return $files;
448 
449  $asset = $am->getAsset($link['minorid']);
450  $asset_webpaths = $asset->getWebPaths();
451  $asset_webpath = $asset_webpaths[0];
452 
453  if (!is_null($asset)) {
454  if (is_a($asset, 'folder')) {
455  $depth++;
456  $files[$depth]['name'] = $asset->name;
457  $files[$depth]['path'] = $asset->data_path.'/'.$asset->name;
458  $files[$depth]['root'] = $parent;
459  $files[$depth]['dir'] = 1;
460  $files[$depth]['webpath'] = $asset_webpath;
461  $files += $this->_getFiles($asset->id, $filetypes, $depth);
462  } else {
463  if (!empty($filetypes)) {
464  foreach ($filetypes as $type) {
465  if ($type != 'folder') {
466  if (is_a($asset, $type)) {
467  $depth++;
468  $files[$depth]['name'] = $asset->name;
469  $files[$depth]['path'] = $asset->data_path.'/'.$asset->name;
470  $files[$depth]['root'] = $parent;
471  $files[$depth]['dir'] = 0;
472  $files[$depth]['webpath'] = $asset_webpath;
473  }//end if
474  }//end if
475  }//end foreach
476  } else {
477  $depth++;
478  $files[$depth]['name'] = $asset->name;
479  $files[$depth]['path'] = $asset->data_path.'/'.$asset->name;
480  $files[$depth]['root'] = $parent;
481  $files[$depth]['dir'] = 0;
482  $files[$depth]['webpath'] = $asset_webpath;
483  }//end if
484  }//end if
485  }//end if
486  }//end foreach
487 
488  return $files;
489 
490  }//end _processFiles()
491 
492 
501  function _cleanup($base)
502  {
503  // Error checking
504  if (!is_string($base) || empty($base)) {
505  return FALSE;
506  }
507 
508  $safe_to_remove = FALSE;
509 
510  if (is_dir($base)) {
511  $base_dir = opendir($base);
512  while (FALSE !== ($file = readdir($base_dir))) {
513  if ($file == '.' || $file == '..') {
514  continue;
515  }
516  $current_file = $base.'/'.$file;
517  if (is_dir($current_file)) {
518  $next = $this->_cleanup($current_file);
519  if (!$next) {
520  trigger_localised_error('CMS0106', E_USER_NOTICE);
521  return FALSE;
522  }
523  } else {
524  $delete_file = unlink($current_file);
525  if (!$delete_file) {
526  trigger_localised_error('CMS0106', E_USER_NOTICE);
527  return FALSE;
528  }
529  }
530  }
531  closedir($base_dir);
532 
533  // Check if empty
534  $check = opendir($base);
535  $files = Array();
536  while (FALSE !== ($filename = readdir($check))) {
537  $files[] = $filename;
538  }
539  sort($files);
540 
541  if ((count($files) == 2) && isset($files[1]) && $files[0] == '.' && $files[1] == '..') {
542  $safe_to_remove = TRUE;
543  }
544  closedir($check);
545 
546  if ($safe_to_remove) {
547  if (!rmdir($base)) return FALSE;
548  } else {
549  return FALSE;
550  }
551  } else {
552  return FALSE;
553  }//end if
554 
555  return TRUE;
556 
557  }//end _cleanup()
558 
559 
560 }//end class
561 
562 ?>