move backends into their own namespace and add support for multiple auth methods

This commit is contained in:
Robin Appelman 2018-03-13 16:18:37 +01:00
commit 29bdebad42
33 changed files with 752 additions and 377 deletions

View file

@ -16,45 +16,50 @@ PHP wrapper for `smbclient` and [`libsmbclient-php`](https://github.com/eduardok
Examples Examples
---- ----
### Upload a file ### ### Connect to a share ###
```php ```php
<?php <?php
use Icewind\SMB\Server; use Icewind\SMB\ServerFactory;
use Icewind\SMB\BasicAuth;
require('vendor/autoload.php'); require('vendor/autoload.php');
$fileToUpload = __FILE__; $serverFactory = new ServerFactory();
$auth = new BasicAuth('workgroup\test', 'test');
$server = $serverFactory->createServer('localhost', $auth);
$server = new Server('localhost', 'test', 'test');
$share = $server->getShare('test'); $share = $server->getShare('test');
```
The server factory will automatically pick between the `smbclient` and `libsmbclient-php`
based backend depending on what is available.
### Using kerberos authentication ###
```php
$serverFactory = new ServerFactory();
$auth = new KerberosAuth();
$server = $serverFactory->createServer('localhost', $auth);
```
Note that this requires a valid kerberos ticket to already be available for php
### Upload a file ###
```php
$share->put($fileToUpload, 'example.txt'); $share->put($fileToUpload, 'example.txt');
``` ```
### Download a file ### ### Download a file ###
```php ```php
<?php
use Icewind\SMB\Server;
require('vendor/autoload.php');
$target = __DIR__ . '/target.txt';
$server = new Server('localhost', 'test', 'test');
$share = $server->getShare('test');
$share->get('example.txt', $target); $share->get('example.txt', $target);
``` ```
### List shares on the remote server ### ### List shares on the remote server ###
```php ```php
<?php
use Icewind\SMB\Server;
require('vendor/autoload.php');
$server = new Server('localhost', 'test', 'test');
$shares = $server->listShares(); $shares = $server->listShares();
foreach ($shares as $share) { foreach ($shares as $share) {
@ -65,13 +70,6 @@ foreach ($shares as $share) {
### List the content of a folder ### ### List the content of a folder ###
```php ```php
<?php
use Icewind\SMB\Server;
require('vendor/autoload.php');
$server = new Server('localhost', 'test', 'test');
$share = $server->getShare('test');
$content = $share->dir('test'); $content = $share->dir('test');
foreach ($content as $info) { foreach ($content as $info) {
@ -83,14 +81,6 @@ foreach ($content as $info) {
### Using read streams ### Using read streams
```php ```php
<?php
use Icewind\SMB\Server;
require('vendor/autoload.php');
$server = new Server('localhost', 'test', 'test');
$share = $server->getShare('test');
$fh = $share->read('test.txt'); $fh = $share->read('test.txt');
echo fread($fh, 4086); echo fread($fh, 4086);
fclose($fh); fclose($fh);
@ -99,53 +89,14 @@ fclose($fh);
### Using write streams ### Using write streams
```php ```php
<?php
use Icewind\SMB\Server;
require('vendor/autoload.php');
$server = new Server('localhost', 'test', 'test');
$share = $server->getShare('test');
$fh = $share->write('test.txt'); $fh = $share->write('test.txt');
fwrite($fh, 'bar'); fwrite($fh, 'bar');
fclose($fh); fclose($fh);
``` ```
### Using libsmbclient-php ###
Install [libsmbclient-php](https://github.com/eduardok/libsmbclient-php)
```php
<?php
use Icewind\SMB\Server;
use Icewind\SMB\NativeServer;
require('vendor/autoload.php');
$fileToUpload = __FILE__;
if (Server::NativeAvailable()) {
$server = new NativeServer('localhost', 'test', 'test');
} else {
echo 'libsmbclient-php not available, falling back to wrapping smbclient';
$server = new Server('localhost', 'test', 'test');
}
$share = $server->getShare('test');
$share->put($fileToUpload, 'example.txt');
```
### Using notify ### Using notify
```php ```php
<?php
use Icewind\SMB\Server;
require('vendor/autoload.php');
$server = new Server('localhost', 'test', 'test');
$share = $server->getShare('test');
$share->notify('')->listen(function (\Icewind\SMB\Change $change) { $share->notify('')->listen(function (\Icewind\SMB\Change $change) {
echo $change->getCode() . ': ' . $change->getPath() . "\n"; echo $change->getCode() . ': ' . $change->getPath() . "\n";
}); });

View file

@ -13,7 +13,7 @@
"icewind/streams": ">=0.2.0" "icewind/streams": ">=0.2.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^4.8" "phpunit/phpunit": "^5.7"
}, },
"autoload" : { "autoload" : {
"psr-4": { "psr-4": {

View file

@ -6,15 +6,14 @@ use Icewind\SMB\Server;
require('vendor/autoload.php'); require('vendor/autoload.php');
$host = 'localhost'; $host = 'localhost';
$user = 'test'; $user = 'test\test';
$password = 'test'; $password = 'test';
$share = 'test'; $share = 'test';
if (Server::NativeAvailable()) { $auth = new \Icewind\SMB\BasicAuth($user, $password);
$server = new NativeServer($host, $user, $password); $serverFactory = new \Icewind\SMB\ServerFactory();
} else {
$server = new Server($host, $user, $password); $server = $serverFactory->createServer($host, $auth);
}
$share = $server->getShare($share); $share = $server->getShare($share);

85
src/AbstractServer.php Normal file
View file

@ -0,0 +1,85 @@
<?php
/**
* @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace Icewind\SMB;
abstract class AbstractServer implements IServer {
const LOCALE = 'en_US.UTF-8';
/**
* @var string $host
*/
protected $host;
/**
* @var IAuth $user
*/
protected $auth;
/**
* @var \Icewind\SMB\System
*/
protected $system;
/**
* @var TimeZoneProvider
*/
protected $timezoneProvider;
/**
* @param string $host
* @param IAuth $auth
* @param System $system
* @param TimeZoneProvider $timeZoneProvider
*/
public function __construct($host, IAuth $auth, System $system, TimeZoneProvider $timeZoneProvider) {
$this->host = $host;
$this->auth = $auth;
$this->system = $system;
$this->timezoneProvider = $timeZoneProvider;
}
/**
* @return IAuth
*/
public function getAuth() {
return $this->auth;
}
/**
* return string
*/
public function getHost() {
return $this->host;
}
/**
* @return string
*/
public function getTimeZone() {
return $this->timezoneProvider->get();
}
public function getSystem() {
return $this->system;
}
}

82
src/BasicAuth.php Normal file
View file

@ -0,0 +1,82 @@
<?php
/**
* @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace Icewind\SMB;
class BasicAuth implements IAuth {
/** @var string */
private $username;
/** @var string */
private $workgroup;
/** @var string */
private $password;
/**
* BasicAuth constructor.
*
* @param string $username
* @param string $password
*/
public function __construct($username, $password) {
list($workgroup, $username) = $this->splitUser($username);
$this->username = $username;
$this->workgroup = $workgroup;
$this->password = $password;
}
/**
* Split workgroup from username
*
* @param $user
* @return string[] [$workgroup, $user]
*/
private function splitUser($user) {
if (strpos($user, '/')) {
return explode('/', $user, 2);
} elseif (strpos($user, '\\')) {
return explode('\\', $user);
} else {
return array(null, $user);
}
}
public function getUsername() {
return $this->username;
}
public function getWorkgroup() {
return $this->workgroup;
}
public function getPassword() {
return $this->password;
}
public function getExtraCommandLineArguments() {
return ($this->workgroup) ? '-W ' . escapeshellarg($this->workgroup) : '';
}
public function setExtraSmbClientOptions($smbClientState) {
// noop
}
}

53
src/IAuth.php Normal file
View file

@ -0,0 +1,53 @@
<?php
/**
* @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace Icewind\SMB;
interface IAuth {
/**
* @return string|null
*/
public function getUsername();
/**
* @return string|null
*/
public function getWorkgroup();
/**
* @return string|null
*/
public function getPassword();
/**
* Any extra command line option for smbclient that are required
*
* @return string
*/
public function getExtraCommandLineArguments();
/**
* Set any extra options for libsmbclient that are required
*
* @param resource $smbClientState
*/
public function setExtraSmbClientOptions($smbClientState);
}

View file

@ -8,6 +8,19 @@
namespace Icewind\SMB; namespace Icewind\SMB;
interface IFileInfo { interface IFileInfo {
/*
* Mappings of the DOS mode bits, as returned by smbc_getxattr() when the
* attribute name "system.dos_attr.mode" (or "system.dos_attr.*" or
* "system.*") is specified.
*/
const MODE_READONLY = 0x01;
const MODE_HIDDEN = 0x02;
const MODE_SYSTEM = 0x04;
const MODE_VOLUME_ID = 0x08;
const MODE_DIRECTORY = 0x10;
const MODE_ARCHIVE = 0x20;
const MODE_NORMAL = 0x80;
/** /**
* @return string * @return string
*/ */

64
src/IServer.php Normal file
View file

@ -0,0 +1,64 @@
<?php
/**
* @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace Icewind\SMB;
interface IServer {
/**
* @return IAuth
*/
public function getAuth();
/**
* @return string
*/
public function getHost();
/**
* @return \Icewind\SMB\IShare[]
*
* @throws \Icewind\SMB\Exception\AuthenticationException
* @throws \Icewind\SMB\Exception\InvalidHostException
*/
public function listShares();
/**
* @param string $name
* @return \Icewind\SMB\IShare
*/
public function getShare($name);
/**
* @return string
*/
public function getTimeZone();
/**
* @return System
*/
public function getSystem();
/**
* @param System $system
* @return bool
*/
public static function available(System $system);
}

49
src/KerberosAuth.php Normal file
View file

@ -0,0 +1,49 @@
<?php
/**
* @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace Icewind\SMB;
/**
* Use existing kerberos ticket to authenticate
*/
class KerberosAuth implements IAuth {
public function getUsername() {
return 'dummy';
}
public function getWorkgroup() {
return 'dummy';
}
public function getPassword() {
return null;
}
public function getExtraCommandLineArguments() {
return '-k';
}
public function setExtraSmbClientOptions($smbClientState) {
smbclient_option_set($smbClientState, SMBCLIENT_OPT_USE_KERBEROS, true);
smbclient_option_set($smbClientState, SMBCLIENT_OPT_FALLBACK_AFTER_KERBEROS, false);
}
}

View file

@ -5,7 +5,9 @@
* http://opensource.org/licenses/MIT * http://opensource.org/licenses/MIT
*/ */
namespace Icewind\SMB; namespace Icewind\SMB\Native;
use Icewind\SMB\IFileInfo;
class NativeFileInfo implements IFileInfo { class NativeFileInfo implements IFileInfo {
const MODE_FILE = 0100000; const MODE_FILE = 0100000;
@ -21,7 +23,7 @@ class NativeFileInfo implements IFileInfo {
protected $name; protected $name;
/** /**
* @var \Icewind\SMB\NativeShare * @var NativeShare
*/ */
protected $share; protected $share;
@ -36,7 +38,7 @@ class NativeFileInfo implements IFileInfo {
protected $modeCache; protected $modeCache;
/** /**
* @param \Icewind\SMB\NativeShare $share * @param NativeShare $share
* @param string $path * @param string $path
* @param string $name * @param string $name
* @param array $stat * @param array $stat
@ -113,7 +115,7 @@ class NativeFileInfo implements IFileInfo {
*/ */
public function isReadOnly() { public function isReadOnly() {
$mode = $this->getMode(); $mode = $this->getMode();
return (bool)($mode & FileInfo::MODE_READONLY); return (bool)($mode & IFileInfo::MODE_READONLY);
} }
/** /**
@ -121,7 +123,7 @@ class NativeFileInfo implements IFileInfo {
*/ */
public function isHidden() { public function isHidden() {
$mode = $this->getMode(); $mode = $this->getMode();
return (bool)($mode & FileInfo::MODE_HIDDEN); return (bool)($mode & IFileInfo::MODE_HIDDEN);
} }
/** /**
@ -129,7 +131,7 @@ class NativeFileInfo implements IFileInfo {
*/ */
public function isSystem() { public function isSystem() {
$mode = $this->getMode(); $mode = $this->getMode();
return (bool)($mode & FileInfo::MODE_SYSTEM); return (bool)($mode & IFileInfo::MODE_SYSTEM);
} }
/** /**
@ -137,6 +139,6 @@ class NativeFileInfo implements IFileInfo {
*/ */
public function isArchived() { public function isArchived() {
$mode = $this->getMode(); $mode = $this->getMode();
return (bool)($mode & FileInfo::MODE_ARCHIVE); return (bool)($mode & IFileInfo::MODE_ARCHIVE);
} }
} }

View file

@ -5,7 +5,7 @@
* http://opensource.org/licenses/MIT * http://opensource.org/licenses/MIT
*/ */
namespace Icewind\SMB; namespace Icewind\SMB\Native;
/** /**
* Stream optimized for read only usage * Stream optimized for read only usage
@ -38,7 +38,7 @@ class NativeReadStream extends NativeStream {
* @return resource * @return resource
*/ */
public static function wrap($state, $smbStream, $mode, $url) { public static function wrap($state, $smbStream, $mode, $url) {
stream_wrapper_register('nativesmb', '\Icewind\SMB\NativeReadStream'); stream_wrapper_register('nativesmb', NativeReadStream::class);
$context = stream_context_create(array( $context = stream_context_create(array(
'nativesmb' => array( 'nativesmb' => array(
'state' => $state, 'state' => $state,

View file

@ -5,26 +5,32 @@
* http://opensource.org/licenses/MIT * http://opensource.org/licenses/MIT
*/ */
namespace Icewind\SMB; namespace Icewind\SMB\Native;
class NativeServer extends Server { use Icewind\SMB\AbstractServer;
use Icewind\SMB\IAuth;
use Icewind\SMB\System;
use Icewind\SMB\TimeZoneProvider;
class NativeServer extends AbstractServer {
/** /**
* @var \Icewind\SMB\NativeState * @var NativeState
*/ */
protected $state; protected $state;
/** /**
* @param string $host * @param string $host
* @param string $user * @param IAuth $auth
* @param string $password * @param System $system
* @param TimeZoneProvider $timeZoneProvider
*/ */
public function __construct($host, $user, $password) { public function __construct($host, IAuth $auth, System $system, TimeZoneProvider $timeZoneProvider) {
parent::__construct($host, $user, $password); parent::__construct($host, $auth, $system, $timeZoneProvider);
$this->state = new NativeState(); $this->state = new NativeState();
} }
protected function connect() { protected function connect() {
$this->state->init($this->getWorkgroup(), $this->getUser(), $this->getPassword()); $this->state->init($this->getAuth());
} }
/** /**
@ -52,4 +58,14 @@ class NativeServer extends Server {
public function getShare($name) { public function getShare($name) {
return new NativeShare($this, $name); return new NativeShare($this, $name);
} }
/**
* Check if the smbclient php extension is available
*
* @param System $system
* @return bool
*/
public static function available(System $system) {
return function_exists('smbclient_state_new');
}
} }

View file

@ -5,14 +5,20 @@
* http://opensource.org/licenses/MIT * http://opensource.org/licenses/MIT
*/ */
namespace Icewind\SMB; namespace Icewind\SMB\Native;
use Icewind\SMB\AbstractShare;
use Icewind\SMB\Exception\DependencyException;
use Icewind\SMB\Exception\InvalidPathException; use Icewind\SMB\Exception\InvalidPathException;
use Icewind\SMB\Exception\InvalidResourceException; use Icewind\SMB\Exception\InvalidResourceException;
use Icewind\SMB\INotifyHandler;
use Icewind\SMB\IServer;
use Icewind\SMB\Wrapped\Server;
use Icewind\SMB\Wrapped\Share;
class NativeShare extends AbstractShare { class NativeShare extends AbstractShare {
/** /**
* @var Server $server * @var IServer $server
*/ */
private $server; private $server;
@ -22,12 +28,12 @@ class NativeShare extends AbstractShare {
private $name; private $name;
/** /**
* @var \Icewind\SMB\NativeState $state * @var NativeState $state
*/ */
private $state; private $state;
/** /**
* @param Server $server * @param IServer $server
* @param string $name * @param string $name
*/ */
public function __construct($server, $name) { public function __construct($server, $name) {
@ -47,7 +53,7 @@ class NativeShare extends AbstractShare {
} }
$this->state = new NativeState(); $this->state = new NativeState();
$this->state->init($this->server->getWorkgroup(), $this->server->getUser(), $this->server->getPassword()); $this->state->init($this->server->getAuth());
return $this->state; return $this->state;
} }
@ -295,6 +301,9 @@ class NativeShare extends AbstractShare {
public function notify($path) { public function notify($path) {
// php-smbclient does support notify (https://github.com/eduardok/libsmbclient-php/issues/29) // php-smbclient does support notify (https://github.com/eduardok/libsmbclient-php/issues/29)
// so we use the smbclient based backend for this // so we use the smbclient based backend for this
if (!Server::available($this->server->getSystem())) {
throw new DependencyException('smbclient not found in path for notify command');
}
$share = new Share($this->server, $this->getName()); $share = new Share($this->server, $this->getName());
return $share->notify($path); return $share->notify($path);
} }

View file

@ -5,7 +5,7 @@
* http://opensource.org/licenses/MIT * http://opensource.org/licenses/MIT
*/ */
namespace Icewind\SMB; namespace Icewind\SMB\Native;
use Icewind\SMB\Exception\AlreadyExistsException; use Icewind\SMB\Exception\AlreadyExistsException;
use Icewind\SMB\Exception\ConnectionRefusedException; use Icewind\SMB\Exception\ConnectionRefusedException;
@ -20,6 +20,7 @@ use Icewind\SMB\Exception\NotEmptyException;
use Icewind\SMB\Exception\NotFoundException; use Icewind\SMB\Exception\NotFoundException;
use Icewind\SMB\Exception\OutOfSpaceException; use Icewind\SMB\Exception\OutOfSpaceException;
use Icewind\SMB\Exception\TimedOutException; use Icewind\SMB\Exception\TimedOutException;
use Icewind\SMB\IAuth;
/** /**
* Low level wrapper for libsmbclient-php with error handling * Low level wrapper for libsmbclient-php with error handling
@ -63,7 +64,7 @@ class NativeState {
protected function testResult($result, $uri) { protected function testResult($result, $uri) {
if ($result === false or $result === null) { if ($result === false or $result === null) {
// smb://host/share/path // smb://host/share/path
if (is_string($uri)) { if (is_string($uri) && count(explode('/', $uri, 5)) > 4) {
list(, , , , $path) = explode('/', $uri, 5); list(, , , , $path) = explode('/', $uri, 5);
$path = '/' . $path; $path = '/' . $path;
} else { } else {
@ -74,18 +75,17 @@ class NativeState {
} }
/** /**
* @param string $workGroup * @param IAuth $auth
* @param string $user
* @param string $password
* @return bool * @return bool
*/ */
public function init($workGroup, $user, $password) { public function init(IAuth $auth) {
if ($this->connected) { if ($this->connected) {
return true; return true;
} }
$this->state = smbclient_state_new(); $this->state = smbclient_state_new();
smbclient_option_set($this->state, SMBCLIENT_OPT_AUTO_ANONYMOUS_LOGIN, false); smbclient_option_set($this->state, SMBCLIENT_OPT_AUTO_ANONYMOUS_LOGIN, false);
$result = @smbclient_state_init($this->state, $workGroup, $user, $password); $auth->setExtraSmbClientOptions($this->state);
$result = @smbclient_state_init($this->state, $auth->getWorkgroup(), $auth->getUsername(), $auth->getPassword());
$this->testResult($result, ''); $this->testResult($result, '');
$this->connected = true; $this->connected = true;

View file

@ -5,7 +5,7 @@
* http://opensource.org/licenses/MIT * http://opensource.org/licenses/MIT
*/ */
namespace Icewind\SMB; namespace Icewind\SMB\Native;
use Icewind\SMB\Exception\Exception; use Icewind\SMB\Exception\Exception;
use Icewind\SMB\Exception\InvalidRequestException; use Icewind\SMB\Exception\InvalidRequestException;
@ -18,7 +18,7 @@ class NativeStream implements File {
public $context; public $context;
/** /**
* @var \Icewind\SMB\NativeState * @var NativeState
*/ */
protected $state; protected $state;
@ -47,7 +47,7 @@ class NativeStream implements File {
* @return resource * @return resource
*/ */
public static function wrap($state, $smbStream, $mode, $url) { public static function wrap($state, $smbStream, $mode, $url) {
stream_wrapper_register('nativesmb', '\Icewind\SMB\NativeStream'); stream_wrapper_register('nativesmb', NativeStream::class);
$context = stream_context_create(array( $context = stream_context_create(array(
'nativesmb' => array( 'nativesmb' => array(
'state' => $state, 'state' => $state,

View file

@ -5,7 +5,7 @@
* http://opensource.org/licenses/MIT * http://opensource.org/licenses/MIT
*/ */
namespace Icewind\SMB; namespace Icewind\SMB\Native;
/** /**
* Stream optimized for write only usage * Stream optimized for write only usage
@ -38,7 +38,7 @@ class NativeWriteStream extends NativeStream {
* @return resource * @return resource
*/ */
public static function wrap($state, $smbStream, $mode, $url) { public static function wrap($state, $smbStream, $mode, $url) {
stream_wrapper_register('nativesmb', '\Icewind\SMB\NativeWriteStream'); stream_wrapper_register('nativesmb', NativeWriteStream::class);
$context = stream_context_create(array( $context = stream_context_create(array(
'nativesmb' => array( 'nativesmb' => array(
'state' => $state, 'state' => $state,

View file

@ -1,166 +0,0 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Licensed under the MIT license:
* http://opensource.org/licenses/MIT
*/
namespace Icewind\SMB;
use Icewind\SMB\Exception\AuthenticationException;
use Icewind\SMB\Exception\InvalidHostException;
class Server {
const LOCALE = 'en_US.UTF-8';
/**
* @var string $host
*/
protected $host;
/**
* @var string $user
*/
protected $user;
/**
* @var string $password
*/
protected $password;
/**
* @var string $workgroup
*/
protected $workgroup;
/**
* @var \Icewind\SMB\System
*/
private $system;
/**
* @var TimeZoneProvider
*/
private $timezoneProvider;
/**
* Check if the smbclient php extension is available
*
* @return bool
*/
public static function NativeAvailable() {
return function_exists('smbclient_state_new');
}
/**
* @param string $host
* @param string $user
* @param string $password
*/
public function __construct($host, $user, $password) {
$this->host = $host;
list($workgroup, $user) = $this->splitUser($user);
$this->user = $user;
$this->workgroup = $workgroup;
$this->password = $password;
$this->system = new System();
$this->timezoneProvider = new TimeZoneProvider($host, $this->system);
}
/**
* Split workgroup from username
*
* @param $user
* @return string[] [$workgroup, $user]
*/
public function splitUser($user) {
if (strpos($user, '/')) {
return explode('/', $user, 2);
} elseif (strpos($user, '\\')) {
return explode('\\', $user);
} else {
return array(null, $user);
}
}
/**
* @return string
*/
public function getAuthString() {
return $this->user . '%' . $this->password;
}
/**
* @return string
*/
public function getUser() {
return $this->user;
}
/**
* @return string
*/
public function getPassword() {
return $this->password;
}
/**
* return string
*/
public function getHost() {
return $this->host;
}
/**
* @return string
*/
public function getWorkgroup() {
return $this->workgroup;
}
/**
* @return \Icewind\SMB\IShare[]
*
* @throws \Icewind\SMB\Exception\AuthenticationException
* @throws \Icewind\SMB\Exception\InvalidHostException
*/
public function listShares() {
$workgroupArgument = ($this->workgroup) ? ' -W ' . escapeshellarg($this->workgroup) : '';
$command = sprintf('%s %s --authentication-file=%s -gL %s',
$this->system->getSmbclientPath(),
$workgroupArgument,
System::getFD(3),
escapeshellarg($this->getHost())
);
$connection = new RawConnection($command);
$connection->writeAuthentication($this->getUser(), $this->getPassword());
$connection->connect();
$output = $connection->readAll();
$parser = new Parser($this->timezoneProvider);
$parser->checkConnectionError($output[0]);
$shareNames = $parser->parseListShares($output);
$shares = array();
foreach ($shareNames as $name => $description) {
$shares[] = $this->getShare($name);
}
return $shares;
}
/**
* @param string $name
* @return \Icewind\SMB\IShare
*/
public function getShare($name) {
return new Share($this, $name, $this->system);
}
/**
* @return string
*/
public function getTimeZone() {
return $this->timezoneProvider->get();
}
}

64
src/ServerFactory.php Normal file
View file

@ -0,0 +1,64 @@
<?php
/**
* @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace Icewind\SMB;
use Icewind\SMB\Exception\DependencyException;
use Icewind\SMB\Native\NativeServer;
use Icewind\SMB\Wrapped\Server;
class ServerFactory {
const BACKENDS = [
NativeServer::class,
Server::class
];
/** @var System|null */
private $system = null;
/**
* @param $host
* @param IAuth $credentials
* @return IServer
* @throws DependencyException
*/
public function createServer($host, IAuth $credentials) {
foreach (self::BACKENDS as $backend) {
if (call_user_func("$backend::available", $this->getSystem())) {
return new $backend($host, $credentials, $this->getSystem(), new TimeZoneProvider($host, $this->getSystem()));
}
}
throw new DependencyException('No valid backend available, ensure smbclient is in the path or php-smbclient is installed');
}
/**
* @return System
*/
private function getSystem() {
if (is_null($this->system)) {
$this->system = new System();
}
return $this->system;
}
}

View file

@ -5,7 +5,7 @@
* http://opensource.org/licenses/MIT * http://opensource.org/licenses/MIT
*/ */
namespace Icewind\SMB; namespace Icewind\SMB\Wrapped;
use Icewind\SMB\Exception\AuthenticationException; use Icewind\SMB\Exception\AuthenticationException;
use Icewind\SMB\Exception\ConnectException; use Icewind\SMB\Exception\ConnectException;

View file

@ -5,7 +5,7 @@
* http://opensource.org/licenses/MIT * http://opensource.org/licenses/MIT
*/ */
namespace Icewind\SMB; namespace Icewind\SMB\Wrapped;
class ErrorCodes { class ErrorCodes {
/** /**

View file

@ -5,22 +5,11 @@
* http://opensource.org/licenses/MIT * http://opensource.org/licenses/MIT
*/ */
namespace Icewind\SMB; namespace Icewind\SMB\Wrapped;
use Icewind\SMB\IFileInfo;
class FileInfo implements IFileInfo { class FileInfo implements IFileInfo {
/*
* Mappings of the DOS mode bits, as returned by smbc_getxattr() when the
* attribute name "system.dos_attr.mode" (or "system.dos_attr.*" or
* "system.*") is specified.
*/
const MODE_READONLY = 0x01;
const MODE_HIDDEN = 0x02;
const MODE_SYSTEM = 0x04;
const MODE_VOLUME_ID = 0x08;
const MODE_DIRECTORY = 0x10;
const MODE_ARCHIVE = 0x20;
const MODE_NORMAL = 0x80;
/** /**
* @var string * @var string
*/ */
@ -93,34 +82,34 @@ class FileInfo implements IFileInfo {
* @return bool * @return bool
*/ */
public function isDirectory() { public function isDirectory() {
return (bool)($this->mode & self::MODE_DIRECTORY); return (bool)($this->mode & IFileInfo::MODE_DIRECTORY);
} }
/** /**
* @return bool * @return bool
*/ */
public function isReadOnly() { public function isReadOnly() {
return (bool)($this->mode & self::MODE_READONLY); return (bool)($this->mode & IFileInfo::MODE_READONLY);
} }
/** /**
* @return bool * @return bool
*/ */
public function isHidden() { public function isHidden() {
return (bool)($this->mode & self::MODE_HIDDEN); return (bool)($this->mode & IFileInfo::MODE_HIDDEN);
} }
/** /**
* @return bool * @return bool
*/ */
public function isSystem() { public function isSystem() {
return (bool)($this->mode & self::MODE_SYSTEM); return (bool)($this->mode & IFileInfo::MODE_SYSTEM);
} }
/** /**
* @return bool * @return bool
*/ */
public function isArchived() { public function isArchived() {
return (bool)($this->mode & self::MODE_ARCHIVE); return (bool)($this->mode & IFileInfo::MODE_ARCHIVE);
} }
} }

View file

@ -6,11 +6,13 @@
* *
*/ */
namespace Icewind\SMB; namespace Icewind\SMB\Wrapped;
use Icewind\SMB\Change;
use Icewind\SMB\Exception\Exception; use Icewind\SMB\Exception\Exception;
use Icewind\SMB\Exception\RevisionMismatchException; use Icewind\SMB\Exception\RevisionMismatchException;
use Icewind\SMB\INotifyHandler;
class NotifyHandler implements INotifyHandler { class NotifyHandler implements INotifyHandler {
/** /**

View file

@ -5,7 +5,7 @@
* http://opensource.org/licenses/MIT * http://opensource.org/licenses/MIT
*/ */
namespace Icewind\SMB; namespace Icewind\SMB\Wrapped;
use Icewind\SMB\Exception\AccessDeniedException; use Icewind\SMB\Exception\AccessDeniedException;
use Icewind\SMB\Exception\AlreadyExistsException; use Icewind\SMB\Exception\AlreadyExistsException;
@ -19,6 +19,7 @@ use Icewind\SMB\Exception\InvalidTypeException;
use Icewind\SMB\Exception\NoLoginServerException; use Icewind\SMB\Exception\NoLoginServerException;
use Icewind\SMB\Exception\NotEmptyException; use Icewind\SMB\Exception\NotEmptyException;
use Icewind\SMB\Exception\NotFoundException; use Icewind\SMB\Exception\NotFoundException;
use Icewind\SMB\TimeZoneProvider;
class Parser { class Parser {
const MSG_NOT_FOUND = 'Error opening local file '; const MSG_NOT_FOUND = 'Error opening local file ';
@ -45,7 +46,7 @@ class Parser {
]; ];
/** /**
* @param \Icewind\SMB\TimeZoneProvider $timeZoneProvider * @param TimeZoneProvider $timeZoneProvider
*/ */
public function __construct(TimeZoneProvider $timeZoneProvider) { public function __construct(TimeZoneProvider $timeZoneProvider) {
$this->timeZoneProvider = $timeZoneProvider; $this->timeZoneProvider = $timeZoneProvider;

View file

@ -5,7 +5,7 @@
* http://opensource.org/licenses/MIT * http://opensource.org/licenses/MIT
*/ */
namespace Icewind\SMB; namespace Icewind\SMB\Wrapped;
use Icewind\SMB\Exception\ConnectException; use Icewind\SMB\Exception\ConnectException;
use Icewind\SMB\Exception\ConnectionException; use Icewind\SMB\Exception\ConnectionException;

70
src/Wrapped/Server.php Normal file
View file

@ -0,0 +1,70 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Licensed under the MIT license:
* http://opensource.org/licenses/MIT
*/
namespace Icewind\SMB\Wrapped;
use Icewind\SMB\AbstractServer;
use Icewind\SMB\System;
class Server extends AbstractServer {
/**
* Check if the smbclient php extension is available
*
* @return bool
*/
public static function available(System $system) {
return $system->getSmbclientPath();
}
private function getAuthFileArgument() {
if ($this->getAuth()->getUsername()) {
return '--authentication-file=' . System::getFD(3);
} else {
return '';
}
}
/**
* @return \Icewind\SMB\IShare[]
*
* @throws \Icewind\SMB\Exception\AuthenticationException
* @throws \Icewind\SMB\Exception\InvalidHostException
*/
public function listShares() {
$command = sprintf('%s %s %s -L %s',
$this->system->getSmbclientPath(),
$this->getAuthFileArgument(),
$this->getAuth()->getExtraCommandLineArguments(),
escapeshellarg('//' . $this->getHost())
);
$connection = new RawConnection($command);
$connection->writeAuthentication($this->getAuth()->getUsername(), $this->getAuth()->getPassword());
$connection->connect();
$output = $connection->readAll();
$parser = new Parser($this->timezoneProvider);
if (isset($output[0])) {
$parser->checkConnectionError($output[0]);
}
$shareNames = $parser->parseListShares($output);
$shares = array();
foreach ($shareNames as $name => $description) {
$shares[] = $this->getShare($name);
}
return $shares;
}
/**
* @param string $name
* @return \Icewind\SMB\IShare
*/
public function getShare($name) {
return new Share($this, $name, $this->system);
}
}

View file

@ -5,18 +5,23 @@
* http://opensource.org/licenses/MIT * http://opensource.org/licenses/MIT
*/ */
namespace Icewind\SMB; namespace Icewind\SMB\Wrapped;
use Icewind\SMB\AbstractShare;
use Icewind\SMB\Exception\ConnectionException; use Icewind\SMB\Exception\ConnectionException;
use Icewind\SMB\Exception\DependencyException; use Icewind\SMB\Exception\DependencyException;
use Icewind\SMB\Exception\FileInUseException; use Icewind\SMB\Exception\FileInUseException;
use Icewind\SMB\Exception\InvalidTypeException; use Icewind\SMB\Exception\InvalidTypeException;
use Icewind\SMB\Exception\NotFoundException; use Icewind\SMB\Exception\NotFoundException;
use Icewind\SMB\INotifyHandler;
use Icewind\SMB\IServer;
use Icewind\SMB\System;
use Icewind\SMB\TimeZoneProvider;
use Icewind\Streams\CallbackWrapper; use Icewind\Streams\CallbackWrapper;
class Share extends AbstractShare { class Share extends AbstractShare {
/** /**
* @var Server $server * @var IServer $server
*/ */
private $server; private $server;
@ -31,21 +36,21 @@ class Share extends AbstractShare {
public $connection; public $connection;
/** /**
* @var \Icewind\SMB\Parser * @var Parser
*/ */
protected $parser; protected $parser;
/** /**
* @var \Icewind\SMB\System * @var System
*/ */
private $system; private $system;
/** /**
* @param Server $server * @param IServer $server
* @param string $name * @param string $name
* @param System $system * @param System $system
*/ */
public function __construct($server, $name, System $system = null) { public function __construct(IServer $server, $name, System $system = null) {
parent::__construct(); parent::__construct();
$this->server = $server; $this->server = $server;
$this->name = $name; $this->name = $name;
@ -53,21 +58,24 @@ class Share extends AbstractShare {
$this->parser = new Parser(new TimeZoneProvider($this->server->getHost(), $this->system)); $this->parser = new Parser(new TimeZoneProvider($this->server->getHost(), $this->system));
} }
protected function getConnection() { private function getAuthFileArgument() {
$workgroupArgument = ($this->server->getWorkgroup()) ? ' -W ' . escapeshellarg($this->server->getWorkgroup()) : ''; if ($this->server->getAuth()->getUsername()) {
$smbClientPath = $this->system->getSmbclientPath(); return '--authentication-file=' . System::getFD(3);
if (!$smbClientPath) { } else {
throw new DependencyException('Can\'t find smbclient binary in path'); return '';
} }
$command = sprintf('%s%s %s --authentication-file=%s %s', }
protected function getConnection() {
$command = sprintf('%s%s %s %s %s',
$this->system->hasStdBuf() ? 'stdbuf -o0 ' : '', $this->system->hasStdBuf() ? 'stdbuf -o0 ' : '',
$this->system->getSmbclientPath(), $this->system->getSmbclientPath(),
$workgroupArgument, $this->getAuthFileArgument(),
System::getFD(3), $this->server->getAuth()->getExtraCommandLineArguments(),
escapeshellarg('//' . $this->server->getHost() . '/' . $this->name) escapeshellarg('//' . $this->server->getHost() . '/' . $this->name)
); );
$connection = new Connection($command, $this->parser); $connection = new Connection($command, $this->parser);
$connection->writeAuthentication($this->server->getUser(), $this->server->getPassword()); $connection->writeAuthentication($this->server->getAuth()->getUsername(), $this->server->getAuth()->getPassword());
$connection->connect(); $connection->connect();
if (!$connection->isValid()) { if (!$connection->isValid()) {
throw new ConnectionException($connection->readLine()); throw new ConnectionException($connection->readLine());

View file

@ -11,10 +11,11 @@ use Icewind\SMB\Exception\FileInUseException;
use Icewind\SMB\Exception\InvalidPathException; use Icewind\SMB\Exception\InvalidPathException;
use Icewind\SMB\Exception\NotFoundException; use Icewind\SMB\Exception\NotFoundException;
use Icewind\SMB\FileInfo; use Icewind\SMB\FileInfo;
use Icewind\SMB\IFileInfo;
abstract class AbstractShareTest extends TestCase { abstract class AbstractShareTest extends TestCase {
/** /**
* @var \Icewind\SMB\Server $server * @var \Icewind\SMB\IServer $server
*/ */
protected $server; protected $server;
@ -557,49 +558,49 @@ abstract class AbstractShareTest extends TestCase {
$this->share->put($txtFile, $this->root . '/' . $name); $this->share->put($txtFile, $this->root . '/' . $name);
$this->share->setMode($this->root . '/' . $name, FileInfo::MODE_NORMAL); $this->share->setMode($this->root . '/' . $name, IFileInfo::MODE_NORMAL);
$info = $this->share->stat($this->root . '/' . $name); $info = $this->share->stat($this->root . '/' . $name);
$this->assertFalse($info->isReadOnly()); $this->assertFalse($info->isReadOnly());
$this->assertFalse($info->isArchived()); $this->assertFalse($info->isArchived());
$this->assertFalse($info->isSystem()); $this->assertFalse($info->isSystem());
$this->assertFalse($info->isHidden()); $this->assertFalse($info->isHidden());
$this->share->setMode($this->root . '/' . $name, FileInfo::MODE_READONLY); $this->share->setMode($this->root . '/' . $name, IFileInfo::MODE_READONLY);
$info = $this->share->stat($this->root . '/' . $name); $info = $this->share->stat($this->root . '/' . $name);
$this->assertTrue($info->isReadOnly()); $this->assertTrue($info->isReadOnly());
$this->assertFalse($info->isArchived()); $this->assertFalse($info->isArchived());
$this->assertFalse($info->isSystem()); $this->assertFalse($info->isSystem());
$this->assertFalse($info->isHidden()); $this->assertFalse($info->isHidden());
$this->share->setMode($this->root . '/' . $name, FileInfo::MODE_ARCHIVE); $this->share->setMode($this->root . '/' . $name, IFileInfo::MODE_ARCHIVE);
$info = $this->share->stat($this->root . '/' . $name); $info = $this->share->stat($this->root . '/' . $name);
$this->assertFalse($info->isReadOnly()); $this->assertFalse($info->isReadOnly());
$this->assertTrue($info->isArchived()); $this->assertTrue($info->isArchived());
$this->assertFalse($info->isSystem()); $this->assertFalse($info->isSystem());
$this->assertFalse($info->isHidden()); $this->assertFalse($info->isHidden());
$this->share->setMode($this->root . '/' . $name, FileInfo::MODE_READONLY | FileInfo::MODE_ARCHIVE); $this->share->setMode($this->root . '/' . $name, IFileInfo::MODE_READONLY | IFileInfo::MODE_ARCHIVE);
$info = $this->share->stat($this->root . '/' . $name); $info = $this->share->stat($this->root . '/' . $name);
$this->assertTrue($info->isReadOnly()); $this->assertTrue($info->isReadOnly());
$this->assertTrue($info->isArchived()); $this->assertTrue($info->isArchived());
$this->assertFalse($info->isSystem()); $this->assertFalse($info->isSystem());
$this->assertFalse($info->isHidden()); $this->assertFalse($info->isHidden());
$this->share->setMode($this->root . '/' . $name, FileInfo::MODE_HIDDEN); $this->share->setMode($this->root . '/' . $name, IFileInfo::MODE_HIDDEN);
$info = $this->share->stat($this->root . '/' . $name); $info = $this->share->stat($this->root . '/' . $name);
$this->assertFalse($info->isReadOnly()); $this->assertFalse($info->isReadOnly());
$this->assertFalse($info->isArchived()); $this->assertFalse($info->isArchived());
$this->assertFalse($info->isSystem()); $this->assertFalse($info->isSystem());
$this->assertTrue($info->isHidden()); $this->assertTrue($info->isHidden());
$this->share->setMode($this->root . '/' . $name, FileInfo::MODE_SYSTEM); $this->share->setMode($this->root . '/' . $name, IFileInfo::MODE_SYSTEM);
$info = $this->share->stat($this->root . '/' . $name); $info = $this->share->stat($this->root . '/' . $name);
$this->assertFalse($info->isReadOnly()); $this->assertFalse($info->isReadOnly());
$this->assertFalse($info->isArchived()); $this->assertFalse($info->isArchived());
$this->assertTrue($info->isSystem()); $this->assertTrue($info->isSystem());
$this->assertFalse($info->isHidden()); $this->assertFalse($info->isHidden());
$this->share->setMode($this->root . '/' . $name, FileInfo::MODE_NORMAL); $this->share->setMode($this->root . '/' . $name, IFileInfo::MODE_NORMAL);
$info = $this->share->stat($this->root . '/' . $name); $info = $this->share->stat($this->root . '/' . $name);
$this->assertFalse($info->isReadOnly()); $this->assertFalse($info->isReadOnly());
$this->assertFalse($info->isArchived()); $this->assertFalse($info->isArchived());

View file

@ -7,16 +7,27 @@
namespace Icewind\SMB\Test; namespace Icewind\SMB\Test;
use Icewind\SMB\NativeServer; use Icewind\SMB\BasicAuth;
use Icewind\SMB\Native\NativeServer;
use Icewind\SMB\System;
use Icewind\SMB\TimeZoneProvider;
class NativeShareTestTest extends AbstractShareTest { class NativeShareTest extends AbstractShareTest {
public function setUp() { public function setUp() {
$this->requireBackendEnv('libsmbclient'); $this->requireBackendEnv('libsmbclient');
if (!function_exists('smbclient_state_new')) { if (!function_exists('smbclient_state_new')) {
$this->markTestSkipped('libsmbclient php extension not installed'); $this->markTestSkipped('libsmbclient php extension not installed');
} }
$this->config = json_decode(file_get_contents(__DIR__ . '/config.json')); $this->config = json_decode(file_get_contents(__DIR__ . '/config.json'));
$this->server = new NativeServer($this->config->host, $this->config->user, $this->config->password); $this->server = new NativeServer(
$this->config->host,
new BasicAuth(
$this->config->user,
$this->config->password
),
new System(),
new TimeZoneProvider($this->config->host, new System())
);
$this->share = $this->server->getShare($this->config->share); $this->share = $this->server->getShare($this->config->share);
if ($this->config->root) { if ($this->config->root) {
$this->root = '/' . $this->config->root . '/' . uniqid(); $this->root = '/' . $this->config->root . '/' . uniqid();

View file

@ -7,16 +7,19 @@
namespace Icewind\SMB\Test; namespace Icewind\SMB\Test;
use Icewind\SMB\NativeServer; use Icewind\SMB\BasicAuth;
use Icewind\SMB\Native\NativeServer;
use Icewind\SMB\System;
use Icewind\SMB\TimeZoneProvider;
class NativeStreamTest extends TestCase { class NativeStreamTest extends TestCase {
/** /**
* @var \Icewind\SMB\Server $server * @var \Icewind\SMB\IServer $server
*/ */
protected $server; protected $server;
/** /**
* @var \Icewind\SMB\NativeShare $share * @var \Icewind\SMB\Native\NativeShare $share
*/ */
protected $share; protected $share;
@ -33,7 +36,15 @@ class NativeStreamTest extends TestCase {
$this->markTestSkipped('libsmbclient php extension not installed'); $this->markTestSkipped('libsmbclient php extension not installed');
} }
$this->config = json_decode(file_get_contents(__DIR__ . '/config.json')); $this->config = json_decode(file_get_contents(__DIR__ . '/config.json'));
$this->server = new NativeServer($this->config->host, $this->config->user, $this->config->password); $this->server = new NativeServer(
$this->config->host,
new BasicAuth(
$this->config->user,
$this->config->password
),
new System(),
new TimeZoneProvider($this->config->host, new System())
);
$this->share = $this->server->getShare($this->config->share); $this->share = $this->server->getShare($this->config->share);
if ($this->config->root) { if ($this->config->root) {
$this->root = '/' . $this->config->root . '/' . uniqid(); $this->root = '/' . $this->config->root . '/' . uniqid();

View file

@ -7,10 +7,14 @@
namespace Icewind\SMB\Test; namespace Icewind\SMB\Test;
use Icewind\SMB\BasicAuth;
use Icewind\SMB\Change; use Icewind\SMB\Change;
use Icewind\SMB\Exception\AlreadyExistsException; use Icewind\SMB\Exception\AlreadyExistsException;
use Icewind\SMB\INotifyHandler; use Icewind\SMB\INotifyHandler;
use Icewind\SMB\IShare; use Icewind\SMB\IShare;
use Icewind\SMB\System;
use Icewind\SMB\TimeZoneProvider;
use Icewind\SMB\Wrapped\Server;
class NotifyHandlerTest extends TestCase { class NotifyHandlerTest extends TestCase {
/** /**
@ -23,7 +27,15 @@ class NotifyHandlerTest extends TestCase {
public function setUp() { public function setUp() {
$this->requireBackendEnv('smbclient'); $this->requireBackendEnv('smbclient');
$this->config = json_decode(file_get_contents(__DIR__ . '/config.json')); $this->config = json_decode(file_get_contents(__DIR__ . '/config.json'));
$this->server = new \Icewind\SMB\Server($this->config->host, $this->config->user, $this->config->password); $this->server = new Server(
$this->config->host,
new BasicAuth(
$this->config->user,
$this->config->password
),
new System(),
new TimeZoneProvider($this->config->host, new System())
);
} }
/** /**

View file

@ -8,19 +8,20 @@
namespace Icewind\SMB\Test; namespace Icewind\SMB\Test;
use Icewind\SMB\FileInfo; use Icewind\SMB\IFileInfo;
use Icewind\SMB\Wrapped\FileInfo;
class ParserTest extends \PHPUnit_Framework_TestCase { class ParserTest extends \PHPUnit_Framework_TestCase {
public function modeProvider() { public function modeProvider() {
return array( return array(
array('D', FileInfo::MODE_DIRECTORY), array('D', IFileInfo::MODE_DIRECTORY),
array('A', FileInfo::MODE_ARCHIVE), array('A', IFileInfo::MODE_ARCHIVE),
array('S', FileInfo::MODE_SYSTEM), array('S', IFileInfo::MODE_SYSTEM),
array('H', FileInfo::MODE_HIDDEN), array('H', IFileInfo::MODE_HIDDEN),
array('R', FileInfo::MODE_READONLY), array('R', IFileInfo::MODE_READONLY),
array('N', FileInfo::MODE_NORMAL), array('N', IFileInfo::MODE_NORMAL),
array('RA', FileInfo::MODE_READONLY | FileInfo::MODE_ARCHIVE), array('RA', IFileInfo::MODE_READONLY | IFileInfo::MODE_ARCHIVE),
array('RAH', FileInfo::MODE_READONLY | FileInfo::MODE_ARCHIVE | FileInfo::MODE_HIDDEN) array('RAH', IFileInfo::MODE_READONLY | IFileInfo::MODE_ARCHIVE | IFileInfo::MODE_HIDDEN)
); );
} }
@ -42,7 +43,7 @@ class ParserTest extends \PHPUnit_Framework_TestCase {
* @dataProvider modeProvider * @dataProvider modeProvider
*/ */
public function testParseMode($string, $mode) { public function testParseMode($string, $mode) {
$parser = new \Icewind\SMB\Parser($this->getTimeZoneProvider('UTC')); $parser = new \Icewind\SMB\Wrapped\Parser($this->getTimeZoneProvider('UTC'));
$this->assertEquals($mode, $parser->parseMode($string), 'Failed parsing ' . $string); $this->assertEquals($mode, $parser->parseMode($string), 'Failed parsing ' . $string);
} }
@ -60,7 +61,7 @@ class ParserTest extends \PHPUnit_Framework_TestCase {
), ),
array( array(
'mtime' => strtotime('12 Oct 2013 19:05:58 CEST'), 'mtime' => strtotime('12 Oct 2013 19:05:58 CEST'),
'mode' => FileInfo::MODE_NORMAL, 'mode' => IFileInfo::MODE_NORMAL,
'size' => 29634 'size' => 29634
) )
), ),
@ -76,7 +77,7 @@ class ParserTest extends \PHPUnit_Framework_TestCase {
), ),
array( array(
'mtime' => strtotime('12 Oct 2013 19:05:58 CEST'), 'mtime' => strtotime('12 Oct 2013 19:05:58 CEST'),
'mode' => FileInfo::MODE_DIRECTORY, 'mode' => IFileInfo::MODE_DIRECTORY,
'size' => 29634 'size' => 29634
) )
), ),
@ -92,7 +93,7 @@ class ParserTest extends \PHPUnit_Framework_TestCase {
), ),
array( array(
'mtime' => strtotime('12 Oct 2013 19:05:58 CEST'), 'mtime' => strtotime('12 Oct 2013 19:05:58 CEST'),
'mode' => FileInfo::MODE_HIDDEN + FileInfo::MODE_ARCHIVE, 'mode' => IFileInfo::MODE_HIDDEN + IFileInfo::MODE_ARCHIVE,
'size' => 29634 'size' => 29634
) )
) )
@ -103,7 +104,7 @@ class ParserTest extends \PHPUnit_Framework_TestCase {
* @dataProvider statProvider * @dataProvider statProvider
*/ */
public function testStat($output, $stat) { public function testStat($output, $stat) {
$parser = new \Icewind\SMB\Parser($this->getTimeZoneProvider('UTC')); $parser = new \Icewind\SMB\Wrapped\Parser($this->getTimeZoneProvider('UTC'));
$this->assertEquals($stat, $parser->parseStat($output)); $this->assertEquals($stat, $parser->parseStat($output));
} }
@ -119,7 +120,7 @@ class ParserTest extends \PHPUnit_Framework_TestCase {
), ),
array( array(
new FileInfo('/c.pdf', 'c.pdf', 29634, strtotime('12 Oct 2013 19:05:58 CEST'), new FileInfo('/c.pdf', 'c.pdf', 29634, strtotime('12 Oct 2013 19:05:58 CEST'),
FileInfo::MODE_NORMAL) IFileInfo::MODE_NORMAL)
) )
) )
); );
@ -129,7 +130,7 @@ class ParserTest extends \PHPUnit_Framework_TestCase {
* @dataProvider dirProvider * @dataProvider dirProvider
*/ */
public function testDir($output, $dir) { public function testDir($output, $dir) {
$parser = new \Icewind\SMB\Parser($this->getTimeZoneProvider('CEST')); $parser = new \Icewind\SMB\Wrapped\Parser($this->getTimeZoneProvider('CEST'));
$this->assertEquals($dir, $parser->parseDir($output, '')); $this->assertEquals($dir, $parser->parseDir($output, ''));
} }
} }

View file

@ -7,9 +7,14 @@
namespace Icewind\SMB\Test; namespace Icewind\SMB\Test;
use Icewind\SMB\BasicAuth;
use Icewind\SMB\System;
use Icewind\SMB\TimeZoneProvider;
use Icewind\SMB\Wrapped\Server;
class ServerTest extends TestCase { class ServerTest extends TestCase {
/** /**
* @var \Icewind\SMB\Server $server * @var \Icewind\SMB\Wrapped\Server $server
*/ */
private $server; private $server;
@ -18,7 +23,15 @@ class ServerTest extends TestCase {
public function setUp() { public function setUp() {
$this->requireBackendEnv('smbclient'); $this->requireBackendEnv('smbclient');
$this->config = json_decode(file_get_contents(__DIR__ . '/config.json')); $this->config = json_decode(file_get_contents(__DIR__ . '/config.json'));
$this->server = new \Icewind\SMB\Server($this->config->host, $this->config->user, $this->config->password); $this->server = new Server(
$this->config->host,
new BasicAuth(
$this->config->user,
$this->config->password
),
new System(),
new TimeZoneProvider($this->config->host, new System())
);
} }
public function testListShares() { public function testListShares() {
@ -36,7 +49,15 @@ class ServerTest extends TestCase {
*/ */
public function testWrongUserName() { public function testWrongUserName() {
$this->markTestSkipped('This fails for no reason on travis'); $this->markTestSkipped('This fails for no reason on travis');
$server = new \Icewind\SMB\Server($this->config->host, uniqid(), uniqid()); $server = new Server(
$this->config->host,
new BasicAuth(
uniqid(),
uniqid()
),
new System(),
new TimeZoneProvider($this->config->host, new System())
);
$server->listShares(); $server->listShares();
} }
@ -44,7 +65,15 @@ class ServerTest extends TestCase {
* @expectedException \Icewind\SMB\Exception\AuthenticationException * @expectedException \Icewind\SMB\Exception\AuthenticationException
*/ */
public function testWrongPassword() { public function testWrongPassword() {
$server = new \Icewind\SMB\Server($this->config->host, $this->config->user, uniqid()); $server = new Server(
$this->config->host,
new BasicAuth(
$this->config->user,
uniqid()
),
new System(),
new TimeZoneProvider($this->config->host, new System())
);
$server->listShares(); $server->listShares();
} }
@ -52,7 +81,15 @@ class ServerTest extends TestCase {
* @expectedException \Icewind\SMB\Exception\InvalidHostException * @expectedException \Icewind\SMB\Exception\InvalidHostException
*/ */
public function testWrongHost() { public function testWrongHost() {
$server = new \Icewind\SMB\Server(uniqid(), $this->config->user, $this->config->password); $server = new Server(
uniqid(),
new BasicAuth(
$this->config->user,
$this->config->password
),
new System(),
new TimeZoneProvider($this->config->host, new System())
);
$server->listShares(); $server->listShares();
} }
@ -61,7 +98,15 @@ class ServerTest extends TestCase {
* @expectedException \Icewind\SMB\Exception\InvalidHostException * @expectedException \Icewind\SMB\Exception\InvalidHostException
*/ */
public function testHostEscape() { public function testHostEscape() {
$server = new \Icewind\SMB\Server($this->config->host . ';asd', $this->config->user, $this->config->password); $server = new Server(
$this->config->host . ';asd',
new BasicAuth(
$this->config->user,
$this->config->password
),
new System(),
new TimeZoneProvider($this->config->host, new System())
);
$server->listShares(); $server->listShares();
} }
} }

View file

@ -7,13 +7,24 @@
namespace Icewind\SMB\Test; namespace Icewind\SMB\Test;
use Icewind\SMB\Server as NormalServer; use Icewind\SMB\BasicAuth;
use Icewind\SMB\System;
use Icewind\SMB\TimeZoneProvider;
use Icewind\SMB\Wrapped\Server as NormalServer;
class ShareTestTest extends AbstractShareTest { class ShareTest extends AbstractShareTest {
public function setUp() { public function setUp() {
$this->requireBackendEnv('smbclient'); $this->requireBackendEnv('smbclient');
$this->config = json_decode(file_get_contents(__DIR__ . '/config.json')); $this->config = json_decode(file_get_contents(__DIR__ . '/config.json'));
$this->server = new NormalServer($this->config->host, $this->config->user, $this->config->password); $this->server = new NormalServer(
$this->config->host,
new BasicAuth(
$this->config->user,
$this->config->password
),
new System(),
new TimeZoneProvider($this->config->host, new System())
);
$this->share = $this->server->getShare($this->config->share); $this->share = $this->server->getShare($this->config->share);
if ($this->config->root) { if ($this->config->root) {
$this->root = '/' . $this->config->root . '/' . uniqid(); $this->root = '/' . $this->config->root . '/' . uniqid();
@ -29,24 +40,16 @@ class ShareTestTest extends AbstractShareTest {
public function testHostEscape() { public function testHostEscape() {
$this->requireBackendEnv('smbclient'); $this->requireBackendEnv('smbclient');
$this->config = json_decode(file_get_contents(__DIR__ . '/config.json')); $this->config = json_decode(file_get_contents(__DIR__ . '/config.json'));
$this->server = new NormalServer($this->config->host . ';asd', $this->config->user, $this->config->password); $this->server = new NormalServer(
$this->config->host . ';asd',
new BasicAuth(
$this->config->user,
$this->config->password
),
new System(),
new TimeZoneProvider($this->config->host, new System())
);
$share = $this->server->getShare($this->config->share); $share = $this->server->getShare($this->config->share);
$share->dir($this->root); $share->dir($this->root);
} }
/**
* @expectedException \Icewind\SMB\Exception\DependencyException
*/
public function testNoSmbclient() {
$system = $this->getMockBuilder('\Icewind\SMB\System')
->setMethods(['getSmbclientPath'])
->getMock();
$share = new \Icewind\SMB\Share($this->server, 'dummy', $system);
$system->expects($this->any())
->method('getSmbclientPath')
->will($this->returnValue(''));
$share->mkdir('');
}
} }