src/Samba/SambaStreamWrapper.php
<?php
namespace Samba;
class SambaStreamWrapper
{
const PROTOCOL = 'smb';
/**
* @var SambaClient
*/
protected $client;
/**
* @var resource
*/
protected $stream;
/**
* @var SambaUrl
*/
protected $stream_url;
/**
* @var string
*/
protected $mode;
/**
* @var string
*/
protected $tmpfile;
/**
* @var bool
*/
protected $need_flush = false;
/**
* @var array
*/
protected $dir_list = array();
/**
* @var resource
*/
public $context;
/**
* @param SambaClient $client
*/
public function __construct(SambaClient $client = null)
{
$this->client = $client;
}
/**
* @return SambaClient
*/
protected function client()
{
if (null === $this->client) {
$this->client = new SambaClient();
}
return $this->client;
}
/**
* @param string $path
* @param int $options
* @return bool
*/
public function dir_opendir($path, $options)
{
$url = $this->client()->parseUrl($path);
switch ($url->getType()) {
case SambaUrl::TYPE_HOST:
if ($output = $this->client()->look($url)) {
$this->set_dir_cache($output['disk']);
} else {
throw new SambaException("dir_opendir(): list failed for host '{$url->getHost()}'");
}
break;
case SambaUrl::TYPE_SHARE:
case SambaUrl::TYPE_PATH:
$output = $this->client()->dir($url, '\*');
if (isset($output['info'])) {
$this->set_dir_cache(array_keys($output['info']));
} else {
$this->set_dir_cache(array());
}
break;
default:
throw new SambaException('dir_opendir(): error in URL');
}
return true;
}
/**
* @param array $dir
*/
protected function set_dir_cache(array $dir)
{
$this->dir_list = $dir;
reset($this->dir_list);
}
/**
* @return string
*/
public function dir_readdir()
{
list(,$dir) = each($this->dir_list);
return (null !== $dir) ? $dir : false;
}
/**
* @return bool
*/
public function dir_rewinddir()
{
reset($this->dir_list);
return true;
}
/**
* @return bool
*/
public function dir_closedir()
{
$this->set_dir_cache(array());
return true;
}
/**
* @param string $url
* @param string $mode
* @param int $options
* @param string $opened_path
* @return bool
*/
public function stream_open($url, $mode, $options, &$opened_path)
{
$this->mode = $mode;
$this->stream_url = $purl = $this->client()->parseUrl($url);
if (!$purl->isPath()) {
throw new SambaException('stream_open(): error in URL');
}
switch ($mode) {
case 'r':
case 'r+':
case 'rb':
case 'a':
case 'a+':
$this->tmpfile = tempnam('/tmp', 'smb.down.');
$this->client()->get($purl, $this->tmpfile);
break;
case 'w':
case 'w+':
case 'wb':
case 'x':
case 'x+':
$this->tmpfile = tempnam('/tmp', 'smb.up.');
}
$this->stream = fopen($this->tmpfile, $mode);
return true;
}
public function stream_close()
{
fclose($this->stream);
}
/**
* @param int $count
* @return string
*/
public function stream_read($count)
{
return fread($this->stream, $count);
}
/**
* @param string $data
* @return int
*/
public function stream_write($data)
{
$this->need_flush = true;
return fwrite($this->stream, $data);
}
/**
* @return bool
*/
public function stream_eof()
{
return feof($this->stream);
}
/**
* @return int
*/
public function stream_tell()
{
return ftell($this->stream);
}
/**
* @param int $offset
* @param int $whence
* @return int
*/
public function stream_seek($offset, $whence = SEEK_SET)
{
$pos = fseek($this->stream, $offset, $whence);
return 0 === $pos ? true : false;
}
/**
* @return bool
*/
public function stream_flush()
{
if ($this->mode != 'r' && $this->need_flush) {
$this->client()->put($this->stream_url, $this->tmpfile);
$this->need_flush = false;
}
return true;
}
/**
* @return array
*/
public function stream_stat()
{
return $this->url_stat($this->stream_url->getUrl());
}
/**
* @param string $path
* @return bool
*/
public function unlink($path)
{
$url = $this->client()->parseUrl($path);
$this->client()->del($url);
return true;
}
/**
* @param string $path_from
* @param string $path_to
* @return bool
*/
public function rename($path_from, $path_to)
{
$url_from = $this->client()->parseUrl($path_from);
$url_to = $this->client()->parseUrl($path_to);
$this->client()->rename($url_from, $url_to);
return true;
}
/**
* @param string $path
* @param int $mode
* @param int $options
* @return bool
*/
public function mkdir($path, $mode, $options)
{
$url = $this->client()->parseUrl($path);
$this->client()->mkdir($url);
return true;
}
/**
* @param string $path
* @return bool
*/
public function rmdir($path)
{
$url = $this->client()->parseUrl($path);
$this->client()->rmdir($url);
return true;
}
/**
* @param string $path
* @param int $flags
* @return array
*/
public function url_stat($path, $flags = STREAM_URL_STAT_LINK)
{
$url = $this->client()->parseUrl($path);
try {
$info = $this->client()->info($url);
return $this->get_stat($info);
} catch (SambaException $e) {
if ($flags & STREAM_URL_STAT_QUIET) {
return false;
}
throw $e;
}
}
/**
* @param array $info
* @return array
*/
protected function get_stat(array $info)
{
$isFile = (strpos($info['attr'], 'D') === false);
$stat = ($isFile) ? $this->get_file_stat() : $this->get_dir_stat();
$stat[7] = $stat['size']
= $info['size'];
$stat[8] = $stat[9]
= $stat[10]
= $stat['atime']
= $stat['mtime']
= $stat['ctime']
= $info['time'];
return $stat;
}
/**
* @return array
*/
protected function get_dir_stat()
{
return stat('/tmp');
}
/**
* @return array
*/
protected function get_file_stat()
{
return stat('/etc/passwd');
}
public function __destruct()
{
if ($this->tmpfile != '') {
unlink($this->tmpfile);
}
}
/**
* @return bool
*/
public static function register()
{
return stream_wrapper_register(static::PROTOCOL, get_called_class());
}
/**
* @return bool
*/
public static function unregister()
{
return stream_wrapper_unregister(static::PROTOCOL);
}
/**
* @return bool
*/
public static function is_registered()
{
return in_array(static::PROTOCOL, stream_get_wrappers());
}
}