<?php
/**
*
* @author Benjamin Gillissen <hide@address.com>
*
* **************************************************************
Copyright (C) 2009 Benjamin Gillissen
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details at:
http://www.gnu.org/copyleft/gpl.html
* **************************************************************
*/
class file_transfert {
private $src_ref, $src_path, $dst_ref, $dst_path;
private $src_abs, $dst_abs;
private $src_hdl, $dst_hdl;
private $setting = Array( 'isamove'=>FALSE,
'recursive'=>FALSE,
'exclude'=>Array(),
'followlink'=>FALSE,
'buffer'=>8192);
private $Q;
private $Q_mv;
private $cursor;
public function __construct($src_ref, $src_path, $dst_ref, $dst_path){
$this->src_ref = $src_ref;
$this->src_path = $src_path;
$this->dst_ref = $dst_ref;
$this->dst_path = $dst_path;
$this->src_abs = new file_abstract($this->src_ref);
$this->dst_abs = new file_abstract($this->dst_ref);
}
public function set_option($opt, $val){
if ( isset($this->Q) ){
errors::raise("Transfert setting can only be changed before a compute_queue call", CORE_LOG_WARNING, 'FTRANSFERT');
return FALSE;
}
if ( !isset($this->setting[$opt]) ){
errors::raise("Unknow Transfert setting : $opt", CORE_LOG_WARNING, 'FTRANSFERT');
return FALSE;
}
$this->setting[$opt] = $val;
return TRUE;
}
public function get_option($opt){
if ( !isset($this->setting[$opt]) ){
errors::raise("Unknow Transfert setting : $opt", CORE_LOG_WARNING, 'FTRANSFERT');
return FALSE;
}
return $this->setting[$opt];
}
public function get_options(){ return $this->setting; }
private function path_to_path($path){
$buf = split('/', $path);
$f='';
$last = count($buf) - 1;
foreach($buf as $c => &$entry ){
if ( $c != 0 ){
$f .= '/'.$entry;
} else {
$f .= $entry;
}
if ( $entry !== '..' AND $entry !== '.' AND !empty($entry) AND $c != $last ){
$o[] = $f;
}
}
if( isset($o) ){ return $o; }
return Array();
}
public function compute_queue(){
if ( FALSE === $this->src_abs->connect() ){ return FALSE; }
if ( FALSE === $this->dst_abs->connect() ){ return FALSE; }
if ( FALSE === $this->src_abs->exists($this->src_path) ){ return FALSE; }
$this->Q=Array();
$this->Q_mv=Array();
if ( $this->src_abs->isfile($this->src_path) ){
if ( $this->dst_abs->isdir($this->dst_path) ){
$dst = $this->dst_path.'/'.basename($this->src_path);
} elseif ( $this->dst_abs->isfile($this->dst_path) ){
$dst = $this->dst_path;
} else {
$buf = $this->path_to_path($this->dst_path);
foreach($buf as $c => &$f ){
if ( FALSE === $this->dst_abs->isdir($f) ){ $this->Q_append('mkdir', $f); }
}
unset($buf, $c, $f);
$dst = $this->dst_path;
}
$this->Q_append('cp', $this->src_path, $dst);
if ( $this->setting['isamove'] ){ $this->Q_append('rm', $this->src_path); }
} elseif ( $this->src_abs->isdir($this->src_path) ){
if ( FALSE === $this->dst_abs->isdir($this->dst_path) ){
$buf = $this->path_to_path($this->dst_path);
foreach($buf as $c => &$f ){
if ( FALSE === $this->dst_abs->isdir($f) ){ $this->Q_append('mkdir', $f); }
}
unset($buf, $c, $f);
$this->Q_append('mkdir', $this->dst_path);
}
while (FALSE !== ( $entry = $this->src_abs->readdir($this->src_path) )){
$src = $this->src_path.'/'.$entry;
$dst = $this->dst_path.'/'.$entry;
if ( TRUE === $this->setting['recursive'] ){
$this->recur_populate($src, $dst);
} elseif ( TRUE === $this->src_abs->isfile($src) ){
$this->Q_append('cp', $src, $dst);
if ( $this->setting['isamove'] ){ $this->Q_append('rm', $src); }
}
}
}
$this->Q = array_merge($this->Q, $this->Q_mv);
//foreach($this->Q as $k => $act){ echo "Q [$act[0]] [$act[1]] [$act[2]]\n"; }
unset($this->Q_mv);
return TRUE;
}
private function recur_populate($src, $dst){
if ( $this->src_abs->isdir($src) ){
if ( FALSE === $this->dst_abs->isdir($dst) ){ $this->Q_append('mkdir', $dst); }
while (FALSE !== ( $entry = $this->src_abs->readdir($src) )){
$this->recur_populate($src."/".$entry, $dst.'/'.$entry);
}
if ( $this->setting['isamove'] ){ $this->Q_append('rmdir', $src); }
} else {
$this->Q_append('cp', $src, $dst);
if ( $this->setting['isamove'] ){ $this->Q_append('rm', $src); }
}
}
private function Q_append($act, $src, $dst=NULL){
if ( $act === 'rm' OR $act === 'rmdir' ){
$this->Q_mv[CORE::hash()] = Array($act, $src, $dst);
} else {
$this->Q[CORE::hash()] = Array($act, $src, $dst);
}
}
public function list_queue(){
if ( !isset($this->cursor) ){
reset($this->Q);
} elseif ( FALSE === next($this->Q) ){
unset($this->cursor);
return FALSE;
}
$this->cursor = current(&$this->Q);
//echo "QACT [".$this->cursor[0]."] [".$this->cursor[1]."] [".$this->cursor[2]."]\n";
return TRUE;
}
public function process_item(){
if ( !isset($this->cursor) ){ return FALSE; }
$todo = &$this->cursor;
switch($todo[0]){
case 'cp' : return $this->iocp($todo[1], $todo[2]);
case 'mkdir' : return $this->dst_abs->createdir($todo[1]);
case 'mklink' : //to implement into file accessors
break;
case 'rm' : return $this->src_abs->remove($todo[1], FALSE);
break;
case 'rmdir' : return $this->src_abs->remove($todo[1], FALSE);
break;
default : return FALSE;
}
}
private function iocp($src, $dst){
if ( !isset($this->src_hdl) ){
$this->src_hdl = $this->src_abs->file_open($src, 'r');
if ( FALSE === $this->src_hdl ){
errors::raise("IOCP failed, source file could not be opened ( $this->src_ref:$src )", CORE_LOG_ERROR, 'FTRANSFERT');
unset($this->src_hdl);
return FALSE;
}
$this->dst_hdl = $this->dst_abs->file_open($dst, 'w');
if ( FALSE === $this->dst_hdl ){
errors::raise("IOCP failed, destination file could not be opened ( $this->dst_ref:$dst )", CORE_LOG_ERROR, 'FTRANSFERT');
unset($this->src_hdl, $this->dst_hdl);
return FALSE;
}
}
$feof = $this->src_abs->file_end($this->src_hdl);
$buff = $this->src_abs->file_read($this->src_hdl, $this->setting['buffer']);
if ( FALSE != $feof OR FALSE === $buff OR 0 === strlen($buff) ){
$this->src_abs->file_close($this->src_hdl);
$this->dst_abs->file_close($this->dst_hdl);
unset($this->src_hdl, $this->dst_hdl);
return TRUE;
}
if ( FALSE === $this->dst_abs->file_put($this->dst_hdl, $buff) ){
errors::raise("IOCP failed, Buffer could not be write to destination file ( $this->dst_ref:$dst ), removing incomplet file", CORE_LOG_ERROR, 'FTRANSFERT');
$this->src_abs->file_close($this->src_hdl);
$this->dst_abs->file_close($this->dst_hdl);
$this->dst_abs->remove($dst);
unset($this->src_hdl, $this->dst_hdl);
return FALSE;
}
return NULL;
}
}
return TRUE;