Merge pull request 'nix-ci' (#138) from nix-ci into master

Reviewed-on: https://codeberg.org/icewind/SMB/pulls/138
This commit is contained in:
Robin Appelman 2025-10-26 13:43:08 +01:00
commit d91b5b63b1
81 changed files with 4808 additions and 313 deletions

View file

@ -6,6 +6,7 @@ end_of_line=lf
insert_final_newline=false
indent_style=space
indent_size=4
insert_final_newline=true
[{composer.lock,.babelrc,.stylelintrc,.eslintrc,jest.config,*.bowerrc,*.jsb3,*.jsb2,*.json}]
indent_style=space
@ -15,7 +16,7 @@ indent_size=2
indent_style=tab
tab_width=4
[{*.module,*.hphp,*.phtml,*.php5,*.php4,*.php,*.inc}]
[{*.module,*.hphp,*.phtml,*.php5,*.php4,*.php,*.stub,*.inc}]
indent_style=tab
tab_width=4

View file

@ -10,33 +10,29 @@ on:
name: CI
jobs:
php-cs-fixer:
name: PHP-CS-Fixer
runs-on: ubuntu-latest
checks:
name: Nix checks
runs-on: nix
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: https://github.com/shivammathur/setup-php@v2
- uses: https://codeberg.org/icewind/attic-action@v1
with:
php-version: '8.2'
extensions: apcu
- name: Composer
run: composer install
- name: PHP-CS-Fixer
run: |
composer run cs:check
name: link
instance: https://cache.icewind.link
authToken: "${{ secrets.ATTIC_TOKEN }}"
- run: nix flake check --keep-going
php-versions:
runs-on: ubuntu-22.04
runs-on: nix
name: Unit tests - PHP ${{ matrix.php-version }}
strategy:
fail-fast: false
matrix:
php-version:
- "8.2"
- "8.3"
- "8.4"
- "82"
- "83"
- "84"
services:
samba:
@ -44,52 +40,44 @@ jobs:
env:
ACCOUNT_test: test
UID_test: 1000
SAMBA_VOLUME_CONFIG_test: "[test]; path=/tmp; valid users = test; guest ok = no; read only = no; browseable = yes"
SAMBA_VOLUME_CONFIG_test:
"[test]; path=/tmp; valid users = test; guest ok = no; read only =
no; browseable = yes"
steps:
- name: Install packages
env:
DEBIAN_FRONTEND: noninteractive
run: |
sudo apt-get update
sudo apt-get install -y smbclient libsmbclient-dev
- uses: actions/checkout@v4
- name: Setup PHP
uses: https://github.com/shivammathur/setup-php@v2
- uses: https://codeberg.org/icewind/attic-action@v1
with:
php-version: "${{ matrix.php-version }}"
extensions: apcu, smbclient
coverage: pcov
name: link
instance: https://cache.icewind.link
authToken: "${{ secrets.ATTIC_TOKEN }}"
- name: Composer
run: composer install
run: |
cp -r $(nix build .#vendor --print-out-paths --no-link)/vendor vendor
- name: Config
run: |
echo '{"host": "samba","user": "test","password": "test","share": "test","root": ""}' > tests/config.json
- name: Setup phpunit
run: |
nix build .#apps.x86_64-linux.phpunit${{ matrix.php-version }}.program
- name: PHPUnit Tests - smbclient
uses: https://github.com/nick-invision/retry@v2
with:
timeout_minutes: 2
max_attempts: 3
retry_on: timeout
command: php ./vendor/bin/phpunit tests -c tests/phpunit.xml --coverage-clover=coverage.xml
run:
nix run .#phpunit${{ matrix.php-version }} -- tests -c
tests/phpunit.xml
env:
BACKEND: smbclient
- name: PHPUnit Tests - libsmbclient
uses: https://github.com/nick-invision/retry@v2
with:
timeout_minutes: 2
max_attempts: 3
retry_on: timeout
command: php ./vendor/bin/phpunit tests -c tests/phpunit.xml --coverage-clover=coverage.xml
run: |
mkdir -p /var/lock
nix run .#phpunit${{ matrix.php-version }} -- tests -c tests/phpunit.xml
env:
BACKEND: libsmbclient
- uses: https://github.com/codecov/codecov-action@v3
with:
files: ./coverage.xml
smb-versions:
runs-on: ubuntu-22.04
name: Unit tests - Samba ${{ matrix.server-version }} - smbclient ${{ matrix.client-version }}
name:
Unit tests - Samba ${{ matrix.server-version }} - smbclient ${{
matrix.client-version }}
strategy:
fail-fast: false
@ -115,7 +103,9 @@ jobs:
env:
ACCOUNT_test: test
UID_test: 1000
SAMBA_VOLUME_CONFIG_test: "[test]; path=/tmp; valid users = test; guest ok = no; read only = no; browseable = yes"
SAMBA_VOLUME_CONFIG_test:
"[test]; path=/tmp; valid users = test; guest ok = no; read only =
no; browseable = yes"
steps:
- name: Setup smbclient
@ -134,7 +124,6 @@ jobs:
with:
php-version: 8.2
extensions: apcu, smbclient
coverage: pcov
- name: Composer
run: composer install
- name: Config
@ -146,12 +135,9 @@ jobs:
timeout_minutes: 2
max_attempts: 3
retry_on: timeout
command: php ./vendor/bin/phpunit tests -c tests/phpunit.xml --coverage-clover=coverage.xml
command: php ./vendor/bin/phpunit tests -c tests/phpunit.xml
env:
BACKEND: smbclient
- uses: https://github.com/codecov/codecov-action@v3
with:
files: ./coverage.xml
alpine-test:
runs-on: alpine-latest
@ -163,7 +149,9 @@ jobs:
env:
ACCOUNT_test: test
UID_test: 1000
SAMBA_VOLUME_CONFIG_test: "[test]; path=/tmp; valid users = test; guest ok = no; read only = no; browseable = yes"
SAMBA_VOLUME_CONFIG_test:
"[test]; path=/tmp; valid users = test; guest ok = no; read only =
no; browseable = yes"
steps:
- uses: actions/checkout@v4
@ -182,64 +170,6 @@ jobs:
timeout_minutes: 2
max_attempts: 3
retry_on: timeout
command: php ./vendor/bin/phpunit tests -c tests/phpunit.xml --coverage-clover=coverage.xml
command: php ./vendor/bin/phpunit tests -c tests/phpunit.xml
env:
BACKEND: smbclient
static-psalm-analysis:
runs-on: ubuntu-latest
name: Psalm static analysis - PHP ${{ matrix.php-version }}
strategy:
fail-fast: false
matrix:
php-version:
- "8.2"
- "8.3"
- "8.4"
steps:
- name: krb5-dev
env:
DEBIAN_FRONTEND: noninteractive
run: |
sudo apt-get update
sudo apt-get install -y libkrb5-dev libsmbclient-dev
- name: Checkout
uses: actions/checkout@v4
- name: Set up php
uses: https://github.com/shivammathur/setup-php@master
with:
php-version: "${{ matrix.php-version }}"
tools: composer:v2
coverage: none
extensions: apcu, smbclient, krb5
env:
fail-fast: true
- name: Install dependencies
run: composer i
- name: Run coding standards check
run: composer run psalm
phpstan:
name: PHPStan Static Analysis
runs-on: ubuntu-latest
steps:
- name: krb5-dev
run: |
sudo apt-get update
sudo apt-get install -y libkrb5-dev
- uses: actions/checkout@v4
- name: Setup PHP
uses: https://github.com/shivammathur/setup-php@v2
with:
php-version: 8.3
extensions: apcu, smbclient, krb5
env:
fail-fast: true
- name: Composer
run: composer install
- env:
BACKEND: smbclient
run: php ./vendor/bin/phpstan analyse --level 6 src

View file

@ -10,6 +10,6 @@ jobs:
reuse-compliance-check:
runs-on: ubuntu-latest
steps:
- uses: https://github.com/actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
- name: REUSE Compliance Check
uses: https://github.com/fsfe/reuse-action@a46482ca367aef4454a87620aa37c2be4b2f8106 # v3.0.0
- uses: https://github.com/actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
- name: REUSE Compliance Check
uses: https://github.com/fsfe/reuse-action@a46482ca367aef4454a87620aa37c2be4b2f8106 # v3.0.0

4
.gitignore vendored
View file

@ -2,8 +2,8 @@
# SPDX-License-Identifier: MIT
.idea
vendor
composer.lock
.php_cs.cache
listen.php
test.php
*.cache
*.cache
result

View file

@ -5,19 +5,17 @@
* SPDX-License-Identifier: MIT
*/
$finder = PhpCsFixer\Finder::create()
->exclude('vendor')
->in(__DIR__)
;
$finder = PhpCsFixer\Finder::create()->in(__DIR__);
return (new PhpCsFixer\Config())
->setRules([
'@PSR2' => true,
'@PSR2' => true,
'curly_braces_position' => [
'classes_opening_brace' => 'same_line',
'classes_opening_brace' => 'same_line',
'functions_opening_brace' => 'same_line',
],
'array_syntax' => ['syntax' => 'short'],
'braces' => ['position_after_functions_and_oop_constructs' => 'same'],
'array_syntax' => ['syntax' => 'short'],
'braces' => ['position_after_functions_and_oop_constructs' => 'same'],
'binary_operator_spaces' => ['operators' => ['=>' => 'align_single_space']],
])
->setIndent("\t")

View file

@ -2,24 +2,25 @@
- SPDX-FileCopyrightText: 2014 Robin Appelman <robin@icewind.nl>
- SPDX-License-Identifier: MIT
-->
SMB
===
# SMB
[![CI](https://github.com/icewind1991/SMB/actions/workflows/ci.yaml/badge.svg)](https://github.com/icewind1991/SMB/actions/workflows/ci.yaml)
[![codecov](https://codecov.io/gh/icewind1991/SMB/branch/master/graph/badge.svg?token=eTg0P466k6)](https://codecov.io/gh/icewind1991/SMB)
PHP wrapper for `smbclient` and [`libsmbclient-php`](https://github.com/eduardok/libsmbclient-php)
PHP wrapper for `smbclient` and
[`libsmbclient-php`](https://github.com/eduardok/libsmbclient-php)
- Reuses a single `smbclient` instance for multiple requests
- Doesn't leak the password to the process list
- Simple 1-on-1 mapping of SMB commands
- A stream-based api to remove the need for temporary files
- Support for using libsmbclient directly trough [`libsmbclient-php`](https://github.com/eduardok/libsmbclient-php)
- Support for using libsmbclient directly trough
[`libsmbclient-php`](https://github.com/eduardok/libsmbclient-php)
Examples
----
## Examples
### Connect to a share ###
### Connect to a share
```php
<?php
@ -35,10 +36,10 @@ $server = $serverFactory->createServer('localhost', $auth);
$share = $server->getShare('test');
```
The server factory will automatically pick between the `smbclient` and `libsmbclient-php`
based backend depending on what is available.
The server factory will automatically pick between the `smbclient` and
`libsmbclient-php` based backend depending on what is available.
### Using anonymous authentication ###
### Using anonymous authentication
```php
$serverFactory = new ServerFactory();
@ -46,7 +47,7 @@ $auth = new AnonymousAuth();
$server = $serverFactory->createServer('localhost', $auth);
```
### Using kerberos authentication ###
### Using kerberos authentication
There are two ways of using kerberos to authenticate against the smb server:
@ -55,7 +56,8 @@ There are two ways of using kerberos to authenticate against the smb server:
### Using a server ticket
Using a server ticket allows the web server to authenticate against the smb server using an existing machine account.
Using a server ticket allows the web server to authenticate against the smb
server using an existing machine account.
The ticket needs to be available in the environment of the php process.
@ -67,15 +69,18 @@ $server = $serverFactory->createServer('localhost', $auth);
### Re-using a client ticket
By re-using a client ticket you can create a single sign-on setup where the user authenticates against
the web service using kerberos. And the web server can forward that ticket to the smb server, allowing it
to act on the behalf of the user without requiring the user to enter his password.
By re-using a client ticket you can create a single sign-on setup where the user
authenticates against the web service using kerberos. And the web server can
forward that ticket to the smb server, allowing it to act on the behalf of the
user without requiring the user to enter his password.
The setup for such a system is fairly involved and requires roughly the following this
The setup for such a system is fairly involved and requires roughly the
following this
- The web server is authenticated against kerberos with a machine account
- Delegation is enabled for the web server's machine account
- The web server is setup to perform kerberos authentication and save the ticket in it's environment
- The web server is setup to perform kerberos authentication and save the ticket
in it's environment
- Php has the krb5 extension installed
- The client authenticates using a ticket with forwarding enabled
@ -86,36 +91,36 @@ $auth->setTicket(KerberosTicket::fromEnv());
$server = $serverFactory->createServer('localhost', $auth);
```
### Upload a file ###
### Upload a file
```php
$share->put($fileToUpload, 'example.txt');
```
### Download a file ###
### Download a file
```php
$share->get('example.txt', $target);
```
### List shares on the remote server ###
### List shares on the remote server
```php
$shares = $server->listShares();
foreach ($shares as $share) {
echo $share->getName() . "\n";
echo $share->getName() . "\n";
}
```
### List the content of a folder ###
### List the content of a folder
```php
$content = $share->dir('test');
foreach ($content as $info) {
echo $info->getName() . "\n";
echo "\tsize :" . $info->getSize() . "\n";
echo $info->getName() . "\n";
echo "\tsize :" . $info->getSize() . "\n";
}
```
@ -135,20 +140,22 @@ fwrite($fh, 'bar');
fclose($fh);
```
**Note**: write() will truncate your file to 0bytes. You may open a writeable stream with append() which will point
the cursor to the end of the file or create it if it does not exist yet. (append() is only compatible with libsmbclient-php)
**Note**: write() will truncate your file to 0bytes. You may open a writeable
stream with append() which will point the cursor to the end of the file or
create it if it does not exist yet. (append() is only compatible with
libsmbclient-php)
```php
$fh = $share->append('test.txt');
fwrite($fh, 'bar');
fclose($fh);
```
### Using notify
```php
$share->notify('')->listen(function (\Icewind\SMB\Change $change) {
echo $change->getCode() . ': ' . $change->getPath() . "\n";
echo $change->getCode() . ': ' . $change->getPath() . "\n";
});
```
@ -169,24 +176,30 @@ $options->setMaxProtocol(IOptions::PROTOCOL_SMB3);
$serverFactory = new ServerFactory($options);
```
Note, setting the protocol version is not supported with php-smbclient version 1.0.1 or lower.
Note, setting the protocol version is not supported with php-smbclient version
1.0.1 or lower.
### Customizing system integration
The `smbclient` backend needs to get various information about the system it's running on to function
such as the paths of various binaries or the system timezone.
While the default logic for getting this information should work on most systems, it is possible to customize this behaviour.
The `smbclient` backend needs to get various information about the system it's
running on to function such as the paths of various binaries or the system
timezone. While the default logic for getting this information should work on
most systems, it is possible to customize this behaviour.
In order to customize the integration you provide a custom implementation of `ITimezoneProvider` and/or `ISystem` and pass them as arguments to the `ServerFactory`.
In order to customize the integration you provide a custom implementation of
`ITimezoneProvider` and/or `ISystem` and pass them as arguments to the
`ServerFactory`.
## Testing SMB
Use the following steps to check if the library can connect to your SMB share.
1. Clone this repository or download the source as [zip](https://github.com/icewind1991/SMB/archive/master.zip)
1. Clone this repository or download the source as
[zip](https://github.com/icewind1991/SMB/archive/master.zip)
2. Make sure [composer](https://getcomposer.org/) is installed
3. Run `composer install` in the root of the repository
4. Edit `example.php` with the relevant settings for your share.
5. Run `php example.php`
If everything works correctly then the contents of the share should be outputted.
If everything works correctly then the contents of the share should be
outputted.

View file

@ -1,3 +1,3 @@
# SPDX-FileCopyrightText: 2021 Robin Appelman <robin@icewind.nl>
# SPDX-License-Identifier: MIT
comment: false
comment: false

View file

@ -13,7 +13,7 @@
"icewind/streams": ">=0.7.3"
},
"require-dev": {
"phpunit/phpunit": "^8.5|^9.3.8",
"phpunit/phpunit": "10.5.58",
"friendsofphp/php-cs-fixer": "v3.89.0",
"phpstan/phpstan": "^0.12.57",
"psalm/phar": "6.*"

4402
composer.lock generated Normal file

File diff suppressed because it is too large Load diff

2
composer.lock.license Normal file
View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: 2025 Robin Appelman <robin@icewind.nl>
SPDX-License-Identifier: MIT

103
flake.lock generated
View file

@ -1,17 +1,34 @@
{
"nodes": {
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1747046372,
"narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flakelight": {
"inputs": {
"nixpkgs": [
"flakelight-php",
"nixpkgs"
]
},
"locked": {
"lastModified": 1751892651,
"narHash": "sha256-oLNt26YpwTVj+t7BunpmL+iOUHVt5VLvYB1vnJ7Kw28=",
"lastModified": 1756730985,
"narHash": "sha256-Uv5lLUZfFxQv6RHi1TqLTKso0j0eUVMQQwud29LTV/s=",
"owner": "nix-community",
"repo": "flakelight",
"rev": "f4604c27e117ad54391160ae207b519694b9f845",
"rev": "950121d809b75c32e73684b32ccba8d4e8a67703",
"type": "github"
},
"original": {
@ -20,6 +37,28 @@
"type": "github"
}
},
"flakelight-php": {
"inputs": {
"flakelight": "flakelight",
"nixpkgs": [
"nixpkgs"
],
"phps": "phps"
},
"locked": {
"lastModified": 1761438617,
"narHash": "sha256-9j8gFMuUtd4LTOQkHBltxouXp7lvPxgE0r4uCW96Syk=",
"ref": "refs/heads/main",
"rev": "a7d73a95377469d26c3cde813b32f4e8666dbfbc",
"revCount": 11,
"type": "git",
"url": "https://codeberg.org/icewind/flakelight-php.git"
},
"original": {
"type": "git",
"url": "https://codeberg.org/icewind/flakelight-php.git"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1751741127,
@ -35,11 +74,67 @@
"type": "indirect"
}
},
"phps": {
"inputs": {
"flake-compat": "flake-compat",
"nixpkgs": [
"flakelight-php",
"nixpkgs"
],
"utils": "utils"
},
"locked": {
"lastModified": 1760894074,
"narHash": "sha256-z2EYR3CA5PWTkUr5WkDni2CZQ326msHLPghJLx11pZ0=",
"owner": "fossar",
"repo": "nix-phps",
"rev": "d2807871f18ab2150b1e46b7ee126fe0bf200d4c",
"type": "github"
},
"original": {
"owner": "fossar",
"repo": "nix-phps",
"type": "github"
}
},
"root": {
"inputs": {
"flakelight": "flakelight",
"flakelight-php": "flakelight-php",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
}
},
"root": "root",

View file

@ -1,34 +1,15 @@
{
inputs = {
nixpkgs.url = "nixpkgs/nixos-25.05";
flakelight = {
url = "github:nix-community/flakelight";
flakelight-php = {
url = "git+https://codeberg.org/icewind/flakelight-php.git";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = {flakelight, ...}:
flakelight ./. {
formatters = pkgs: {
"*.php" = pkgs.lib.getExe pkgs.php84.packages.php-cs-fixer;
};
devShell.packages = pkgs: let
php_version = "81";
php = pkgs.pkgs."php${php_version}".buildEnv {
extensions = {
enabled,
all,
}:
enabled
++ (with all; [
dom
simplexml
tokenizer
filter
]);
};
in [
php.packages.composer
php
];
outputs = {flakelight-php, ...}:
flakelight-php ./. {
vendorHash = "sha256-Pj19ClD0+4ONc0i3CJQ3GroaSc/039CixNuTjhXIQy4=";
phpExtensions = all: with all; [smbclient krb5];
testDependencies = pkgs: with pkgs; [samba];
};
}

7
phpstan.neon Normal file
View file

@ -0,0 +1,7 @@
parameters:
level: 7
paths:
- src
stubFiles:
- stubs/krb.stub
- stubs/smbclient.stub

2
phpstan.neon.license Normal file
View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: 2021 Robin Appelman <robin@icewind.nl>
SPDX-License-Identifier: MIT

View file

@ -6,10 +6,11 @@
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
findUnusedCode="false"
ensureOverrideAttribute="false"
>
<stubs>
<file name="tests/krb.phpstub" preloadClasses="true"/>
<file name="tests/smbclient.phpstub" preloadClasses="true"/>
<file name="stubs/krb.stub" preloadClasses="true"/>
<file name="stubs/smbclient.stub" preloadClasses="true"/>
</stubs>
<projectFiles>
<directory name="src" />

View file

@ -1,2 +1,2 @@
SPDX-FileCopyrightText: 2021 Robin Appelman <robin@icewind.nl>
SPDX-FileCopyrightText: 2025 Robin Appelman <robin@icewind.nl>
SPDX-License-Identifier: MIT

View file

@ -6,7 +6,7 @@
namespace Icewind\SMB;
class ACL {
final class ACL {
const TYPE_ALLOW = 0;
const TYPE_DENY = 1;

View file

@ -8,12 +8,12 @@ namespace Icewind\SMB;
use Icewind\SMB\Exception\Exception;
class AnonymousAuth implements IAuth {
final class AnonymousAuth implements IAuth {
public function getUsername(): ?string {
return null;
}
public function getWorkgroup(): ?string {
public function getWorkgroup(): string {
return 'dummy';
}

View file

@ -6,7 +6,7 @@
namespace Icewind\SMB;
class BasicAuth implements IAuth {
final class BasicAuth implements IAuth {
/** @var string */
private $username;
/** @var string|null */
@ -20,7 +20,7 @@ class BasicAuth implements IAuth {
$this->password = $password;
}
public function getUsername(): ?string {
public function getUsername(): string {
return $this->username;
}
@ -28,7 +28,7 @@ class BasicAuth implements IAuth {
return $this->workgroup;
}
public function getPassword(): ?string {
public function getPassword(): string {
return $this->password;
}

View file

@ -6,7 +6,7 @@
namespace Icewind\SMB;
class Change {
final class Change {
/** @var int */
private $code;
/** @var string */

View file

@ -6,5 +6,5 @@
namespace Icewind\SMB\Exception;
class AccessDeniedException extends ConnectException {
final class AccessDeniedException extends ConnectException {
}

View file

@ -6,5 +6,5 @@
namespace Icewind\SMB\Exception;
class AlreadyExistsException extends InvalidRequestException {
final class AlreadyExistsException extends InvalidRequestException {
}

View file

@ -6,5 +6,5 @@
namespace Icewind\SMB\Exception;
class AuthenticationException extends ConnectException {
final class AuthenticationException extends ConnectException {
}

View file

@ -6,5 +6,5 @@
namespace Icewind\SMB\Exception;
class ConnectionAbortedException extends ConnectException {
final class ConnectionAbortedException extends ConnectException {
}

View file

@ -6,5 +6,5 @@
namespace Icewind\SMB\Exception;
class ConnectionException extends ConnectException {
final class ConnectionException extends ConnectException {
}

View file

@ -6,5 +6,5 @@
namespace Icewind\SMB\Exception;
class ConnectionRefusedException extends ConnectException {
final class ConnectionRefusedException extends ConnectException {
}

View file

@ -6,5 +6,5 @@
namespace Icewind\SMB\Exception;
class ConnectionResetException extends ConnectException {
final class ConnectionResetException extends ConnectException {
}

View file

@ -6,5 +6,5 @@
namespace Icewind\SMB\Exception;
class DependencyException extends Exception {
final class DependencyException extends Exception {
}

View file

@ -40,7 +40,7 @@ class Exception extends \Exception {
if (isset($exceptionMap[$error])) {
$exceptionClass = $exceptionMap[$error];
if (is_numeric($error)) {
return new $exceptionClass($path, $error);
return new $exceptionClass($path, (int)$error);
} else {
return new $exceptionClass($path);
}

View file

@ -6,5 +6,5 @@
namespace Icewind\SMB\Exception;
class FileInUseException extends InvalidRequestException {
final class FileInUseException extends InvalidRequestException {
}

View file

@ -6,5 +6,5 @@
namespace Icewind\SMB\Exception;
class ForbiddenException extends InvalidRequestException {
final class ForbiddenException extends InvalidRequestException {
}

View file

@ -6,5 +6,5 @@
namespace Icewind\SMB\Exception;
class HostDownException extends ConnectException {
final class HostDownException extends ConnectException {
}

View file

@ -6,5 +6,5 @@
namespace Icewind\SMB\Exception;
class InvalidArgumentException extends InvalidRequestException {
final class InvalidArgumentException extends InvalidRequestException {
}

View file

@ -6,5 +6,5 @@
namespace Icewind\SMB\Exception;
class InvalidHostException extends ConnectException {
final class InvalidHostException extends ConnectException {
}

View file

@ -6,5 +6,5 @@
namespace Icewind\SMB\Exception;
class InvalidParameterException extends InvalidRequestException {
final class InvalidParameterException extends InvalidRequestException {
}

View file

@ -6,5 +6,5 @@
namespace Icewind\SMB\Exception;
class InvalidPathException extends InvalidRequestException {
final class InvalidPathException extends InvalidRequestException {
}

View file

@ -6,5 +6,5 @@
namespace Icewind\SMB\Exception;
class InvalidResourceException extends Exception {
final class InvalidResourceException extends Exception {
}

View file

@ -8,5 +8,5 @@ declare(strict_types=1);
namespace Icewind\SMB\Exception;
class InvalidTicket extends Exception {
final class InvalidTicket extends Exception {
}

View file

@ -6,5 +6,5 @@
namespace Icewind\SMB\Exception;
class InvalidTypeException extends InvalidRequestException {
final class InvalidTypeException extends InvalidRequestException {
}

View file

@ -6,5 +6,5 @@
namespace Icewind\SMB\Exception;
class NoLoginServerException extends ConnectException {
final class NoLoginServerException extends ConnectException {
}

View file

@ -6,5 +6,5 @@
namespace Icewind\SMB\Exception;
class NoRouteToHostException extends ConnectException {
final class NoRouteToHostException extends ConnectException {
}

View file

@ -6,5 +6,5 @@
namespace Icewind\SMB\Exception;
class NotEmptyException extends InvalidRequestException {
final class NotEmptyException extends InvalidRequestException {
}

View file

@ -6,5 +6,5 @@
namespace Icewind\SMB\Exception;
class NotFoundException extends InvalidRequestException {
final class NotFoundException extends InvalidRequestException {
}

View file

@ -6,5 +6,5 @@
namespace Icewind\SMB\Exception;
class OutOfSpaceException extends InvalidRequestException {
final class OutOfSpaceException extends InvalidRequestException {
}

View file

@ -8,7 +8,7 @@ namespace Icewind\SMB\Exception;
use Throwable;
class RevisionMismatchException extends Exception {
final class RevisionMismatchException extends Exception {
public function __construct(string $message = 'Protocol version mismatch', int $code = 0, ?Throwable $previous = null) {
parent::__construct($message, $code, $previous);
}

View file

@ -6,5 +6,5 @@
namespace Icewind\SMB\Exception;
class TimedOutException extends ConnectException {
final class TimedOutException extends ConnectException {
}

View file

@ -15,7 +15,7 @@ use Icewind\SMB\Exception\InvalidTicket;
*
* @deprecated Use `KerberosAuth` with `$auth->setTicket(KerberosTicket::fromEnv())` instead
*/
class KerberosApacheAuth extends KerberosAuth implements IAuth {
final class KerberosApacheAuth extends KerberosAuth implements IAuth {
public function getTicket(): KerberosTicket {
if ($this->ticket === null) {
$ticket = KerberosTicket::fromEnv();

View file

@ -11,7 +11,7 @@ namespace Icewind\SMB;
use Icewind\SMB\Exception\InvalidTicket;
use KRB5CCache;
class KerberosTicket {
final class KerberosTicket {
/** @var KRB5CCache */
private $krb5;
/** @var string */
@ -55,8 +55,16 @@ class KerberosTicket {
return new KerberosTicket($krb5, $ticketName);
}
public static function load(string $ticket): KerberosTicket {
private static function tmpNam(): string {
$tmpFilename = tempnam(sys_get_temp_dir(), "krb5cc_php_");
if ($tmpFilename === false) {
throw new \Exception("Failed to create temporary file for ticket");
}
return $tmpFilename;
}
public static function load(string $ticket): KerberosTicket {
$tmpFilename = self::tmpNam();
file_put_contents($tmpFilename, $ticket);
register_shutdown_function(function () use ($tmpFilename) {
if (file_exists($tmpFilename)) {
@ -74,12 +82,15 @@ class KerberosTicket {
if (substr($this->cacheName, 0, 5) === 'FILE:') {
$ticket = file_get_contents(substr($this->cacheName, 5));
} else {
$tmpFilename = tempnam(sys_get_temp_dir(), "krb5cc_php_");
$tmpFilename = self::tmpNam();
$tmpCacheFile = "FILE:" . $tmpFilename;
$this->krb5->save($tmpCacheFile);
$ticket = file_get_contents($tmpFilename);
unlink($tmpFilename);
}
if ($ticket === false) {
throw new \Exception("Failed to read saved ticket");
}
return $ticket;
}
}

View file

@ -11,7 +11,7 @@ use Icewind\SMB\Exception\Exception;
use Icewind\SMB\Exception\NotFoundException;
use Icewind\SMB\IFileInfo;
class NativeFileInfo implements IFileInfo {
final class NativeFileInfo implements IFileInfo {
/** @var string */
protected $path;
/** @var string */

View file

@ -11,7 +11,7 @@ use Icewind\SMB\StringBuffer;
/**
* Stream optimized for read only usage
*/
class NativeReadStream extends NativeStream {
final class NativeReadStream extends NativeStream {
const CHUNK_SIZE = 1048576; // 1MB chunks
/** @var StringBuffer */
@ -78,7 +78,7 @@ class NativeReadStream extends NativeStream {
return $this->readBuffer->remaining() <= 0 && parent::stream_eof();
}
public function stream_tell() {
public function stream_tell(): int {
return $this->pos;
}

View file

@ -15,7 +15,7 @@ use Icewind\SMB\IShare;
use Icewind\SMB\ISystem;
use Icewind\SMB\ITimeZoneProvider;
class NativeServer extends AbstractServer {
final class NativeServer extends AbstractServer {
/**
* @var NativeState
*/

View file

@ -22,7 +22,7 @@ use Icewind\SMB\IServer;
use Icewind\SMB\Wrapped\Server;
use Icewind\SMB\Wrapped\Share;
class NativeShare extends AbstractShare {
final class NativeShare extends AbstractShare {
/**
* @var IServer $server
*/
@ -204,6 +204,9 @@ class NativeShare extends AbstractShare {
*/
public function put(string $source, string $target): bool {
$sourceHandle = fopen($source, 'rb');
if (!$sourceHandle) {
return false;
}
$targetUrl = $this->buildUrl($target);
$targetHandle = $this->getState()->create($targetUrl);

View file

@ -28,7 +28,7 @@ use Icewind\SMB\IOptions;
/**
* Low level wrapper for libsmbclient-php with error handling
*/
class NativeState {
final class NativeState {
/** @var resource|null */
protected $state = null;
@ -182,6 +182,10 @@ class NativeState {
if (!$this->state) {
throw new ConnectionException("Not connected");
}
/**
* false positive from wrong reflection info
* @phpstan-ignore arguments.count
*/
$result = @smbclient_rename($this->state, $old, $this->state, $new);
$this->testResult($result, $new);

View file

@ -65,6 +65,9 @@ abstract class NativeStream implements File {
if (stream_wrapper_unregister('nativesmb') === false) {
throw new Exception("Failed to unregister stream wrapper");
}
if ($fh === false) {
throw new \Exception("Failed to start stream wrapper");
}
return $fh;
}

View file

@ -11,7 +11,7 @@ use Icewind\SMB\StringBuffer;
/**
* Stream optimized for write only usage
*/
class NativeWriteStream extends NativeStream {
final class NativeWriteStream extends NativeStream {
const CHUNK_SIZE = 1048576; // 1MB chunks
/** @var StringBuffer */
@ -58,7 +58,7 @@ class NativeWriteStream extends NativeStream {
parent::stream_write($this->writeBuffer->flush());
}
public function stream_write($data) {
public function stream_write($data): int {
$written = $this->writeBuffer->push($data);
$this->pos += $written;
@ -79,7 +79,7 @@ class NativeWriteStream extends NativeStream {
return parent::stream_close() && $flushResult;
}
public function stream_tell() {
public function stream_tell(): int {
return $this->pos;
}

View file

@ -6,7 +6,7 @@
namespace Icewind\SMB;
class Options implements IOptions {
final class Options implements IOptions {
/** @var int */
private $timeout = 20;

View file

@ -10,7 +10,7 @@ use Icewind\SMB\Exception\DependencyException;
use Icewind\SMB\Native\NativeServer;
use Icewind\SMB\Wrapped\Server;
class ServerFactory {
final class ServerFactory {
const BACKENDS = [
NativeServer::class,
Server::class

View file

@ -8,7 +8,7 @@ declare(strict_types=1);
namespace Icewind\SMB;
class StringBuffer {
final class StringBuffer {
/** @var string */
private $buffer = "";
/** @var int */

View file

@ -8,7 +8,7 @@ namespace Icewind\SMB;
use Icewind\SMB\Exception\Exception;
class System implements ISystem {
final class System implements ISystem {
/** @var (string|null)[] */
private $paths = [];

View file

@ -5,7 +5,7 @@
*/
namespace Icewind\SMB;
class TimeZoneProvider implements ITimeZoneProvider {
final class TimeZoneProvider implements ITimeZoneProvider {
/**
* @var string[]
*/

View file

@ -14,7 +14,7 @@ use Icewind\SMB\Exception\ConnectionRefusedException;
use Icewind\SMB\Exception\InvalidHostException;
use Icewind\SMB\Exception\NoLoginServerException;
class Connection extends RawConnection {
final class Connection extends RawConnection {
const DELIMITER = 'smb:';
const DELIMITER_LENGTH = 4;
@ -88,7 +88,7 @@ class Connection extends RawConnection {
}
/**
* @param string|bool $promptLine (optional) prompt line that might contain some info about the error
* @param string|false $promptLine (optional) prompt line that might contain some info about the error
* @throws ConnectException
* @return no-return
*/

View file

@ -6,7 +6,7 @@
namespace Icewind\SMB\Wrapped;
class ErrorCodes {
final class ErrorCodes {
/**
* connection errors
*/

View file

@ -9,7 +9,7 @@ namespace Icewind\SMB\Wrapped;
use Icewind\SMB\ACL;
use Icewind\SMB\IFileInfo;
class FileInfo implements IFileInfo {
final class FileInfo implements IFileInfo {
/** @var string */
protected $path;
/** @var string */

View file

@ -11,7 +11,7 @@ use Icewind\SMB\Exception\Exception;
use Icewind\SMB\Exception\RevisionMismatchException;
use Icewind\SMB\INotifyHandler;
class NotifyHandler implements INotifyHandler {
final class NotifyHandler implements INotifyHandler {
/** @var Connection */
private $connection;

View file

@ -20,7 +20,7 @@ use Icewind\SMB\Exception\NoLoginServerException;
use Icewind\SMB\Exception\NotEmptyException;
use Icewind\SMB\Exception\NotFoundException;
class Parser {
final class Parser {
const MSG_NOT_FOUND = 'Error opening local file ';
/**
@ -146,7 +146,7 @@ class Parser {
// A line = explode statement may not fill all array elements
// properly. May happen when accessing non Windows Fileservers
$words = explode(':', $line, 2);
$name = isset($words[0]) ? $words[0] : '';
$name = $words[0];
$value = isset($words[1]) ? $words[1] : '';
$value = trim($value);
@ -159,8 +159,8 @@ class Parser {
throw new Exception("Malformed state response from server");
}
return [
'mtime' => strtotime($data['write_time']),
'mode' => hexdec(substr($data['attributes'], $attributeStart + 1, -1)),
'mtime' => (int)strtotime($data['write_time']),
'mode' => (int)hexdec(substr($data['attributes'], $attributeStart + 1, -1)),
'size' => isset($data['stream']) ? (int)(explode(' ', $data['stream'])[1]) : 0
];
}
@ -182,7 +182,7 @@ class Parser {
list(, $name, $mode, $size, $time) = $matches;
if ($name !== '.' and $name !== '..') {
$mode = $this->parseMode(strtoupper($mode));
$time = strtotime($time . ' ' . $this->timeZone);
$time = (int)strtotime($time . ' ' . $this->timeZone);
$path = $basePath . '/' . $name;
$content[] = new FileInfo($path, $name, (int)$size, $time, $mode, function () use ($aclCallback, $path): array {
return $aclCallback($path);
@ -255,7 +255,7 @@ class Parser {
}
if (substr($mask, 0, 2) === '0x') {
$maskInt = hexdec($mask);
$maskInt = (int)hexdec($mask);
} else {
$maskInt = 0;
foreach (explode('|', $mask) as $maskString) {

View file

@ -77,7 +77,7 @@ class RawConnection {
'COLUMNS' => 8192, // prevent smbclient from line-wrapping it's output
'TZ' => 'UTC',
]);
$this->process = proc_open($this->command, $descriptorSpec, $this->pipes, '/', $env);
$this->process = proc_open($this->command, $descriptorSpec, $this->pipes, '/', $env) ?: null;
if (!$this->isValid()) {
throw new ConnectionException();
}
@ -211,7 +211,9 @@ class RawConnection {
? "username=$user"
: "username=$user\npassword=$password\n";
$this->authStream = fopen('php://temp', 'w+');
/** @var resource $stream */
$stream = fopen('php://temp', 'w+');
$this->authStream = $stream;
fwrite($this->authStream, $auth);
rewind($this->authStream);
}

View file

@ -16,7 +16,7 @@ use Icewind\SMB\Exception\InvalidHostException;
use Icewind\SMB\IShare;
use Icewind\SMB\ISystem;
class Server extends AbstractServer {
final class Server extends AbstractServer {
/**
* Check if the smbclient php extension is available
*

View file

@ -27,7 +27,7 @@ use Icewind\Streams\CallbackWrapper;
use Icewind\SMB\Native\NativeShare;
use Icewind\SMB\Native\NativeServer;
class Share extends AbstractShare {
final class Share extends AbstractShare {
/**
* @var IServer $server
*/

37
stubs/krb.stub Normal file
View file

@ -0,0 +1,37 @@
<?php
/**
* SPDX-FileCopyrightText: 2022 Robin Appelman <robin@icewind.nl>
* SPDX-License-Identifier: MIT
*/
class KRB5CCache {
/**
* @return string[]
*/
public function getEntries(): array {
return [];
}
public function getName(): string {
return "";
}
/**
* @param string[] $flags
*/
public function initKeytab(string $principal, string $keytab, array $flags = []): void {
}
/**
* @param string[] $flags
*/
public function initPassword(string $principal, string $password, array $flags = []): void {
}
public function isValid(): bool {
return false;
}
public function open(string $source): void {
}
public function save(string $destination): void {
}
public function setConfig(string $destination): void {
}
}

View file

@ -59,8 +59,7 @@ function smbclient_option_set($state, int $option, $value) {
#if HAVE_SMBC_SETOPTIONPROTOCOLS
/**
* @param resource $state
* @param mixed $value
* @return mixed
* @return bool
*/
function smbclient_client_protocols($state, string $minproto = null, string $maxproto = null): bool {
}
@ -77,6 +76,7 @@ function smbclient_opendir($state, string $path) {
/**
* @param resource $state
* @param resource $dir
* @return false|string[]
*/
function smbclient_readdir($state, $dir): false|array {
}
@ -90,7 +90,7 @@ function smbclient_closedir($state, $dir): bool {
/**
* @param resource $state
* @return false|resource
* @return false|array<string|int,int>
*/
function smbclient_stat($state, string $path): false|array {
}
@ -98,6 +98,7 @@ function smbclient_stat($state, string $path): false|array {
/**
* @param resource $state
* @param resource $file
* @return false|array<string|int,int>
*/
function smbclient_fstat($state, $file): false|array {
}
@ -190,6 +191,7 @@ function smbclient_utimes($state, string $path, int $mtime = -1, int $atime = -1
/**
* @param resource $state
* @return false|string[]
*/
function smbclient_listxattr($state, string $path): false|array {
}
@ -214,7 +216,7 @@ function smbclient_removexattr($state, string $path, string $name): bool {
/**
* @param resource $state
* @return false|resource
* @return false|array<string|int,int>
*/
function smbclient_statvfs($state, string $path): false|array {
}
@ -222,6 +224,7 @@ function smbclient_statvfs($state, string $path): false|array {
/**
* @param resource $state
* @param resource $file
* @return false|array<string|int,int>
*/
function smbclient_fstatvfs($state, $file): false|array {
}
@ -240,4 +243,4 @@ const SMBCLIENT_OPT_NETBIOS_NAME = 11;
const SMBCLIENT_OPT_WORKGROUP = 12;
const SMBCLIENT_OPT_USER = 13;
const SMBCLIENT_OPT_PORT = 14;
const SMBCLIENT_OPT_TIMEOUT = 15;
const SMBCLIENT_OPT_TIMEOUT = 15;

View file

@ -27,7 +27,7 @@ use Icewind\SMB\Options;
use Icewind\SMB\System;
use Icewind\SMB\TimeZoneProvider;
abstract class AbstractShareTest extends TestCase {
abstract class AbstractShareTestBase extends TestCase {
/**
* @var \Icewind\SMB\IServer $server
*/

View file

@ -15,7 +15,7 @@ use Icewind\SMB\Options;
use Icewind\SMB\System;
use Icewind\SMB\TimeZoneProvider;
class NativeShareTest extends AbstractShareTest {
class NativeShareTest extends AbstractShareTestBase {
public function getServerClass(): string {
$this->requireBackendEnv('libsmbclient');
if (!function_exists('smbclient_state_new')) {

View file

@ -7,6 +7,7 @@
namespace Icewind\SMB\Test;
use Icewind\SMB\BasicAuth;
use Icewind\SMB\IOptions;
use Icewind\SMB\Native\NativeServer;
use Icewind\SMB\Options;
use Icewind\SMB\System;
@ -36,6 +37,9 @@ class NativeStreamTest extends TestCase {
$this->markTestSkipped('libsmbclient php extension not installed');
}
$this->config = json_decode(file_get_contents(__DIR__ . '/config.json'));
$options = new Options();
$options->setMinProtocol(IOptions::PROTOCOL_SMB2);
$options->setMaxProtocol(IOptions::PROTOCOL_SMB3);
$this->server = new NativeServer(
$this->config->host,
new BasicAuth(
@ -45,7 +49,7 @@ class NativeStreamTest extends TestCase {
),
new System(),
new TimeZoneProvider(new System()),
new Options()
$options
);
$this->share = $this->server->getShare($this->config->share);
if ($this->config->root) {

View file

@ -12,7 +12,7 @@ use Icewind\SMB\Exception\AlreadyExistsException;
use Icewind\SMB\Exception\Exception;
use Icewind\SMB\Exception\RevisionMismatchException;
use Icewind\SMB\INotifyHandler;
use Icewind\SMB\IShare;
use Icewind\SMB\ISystem;
use Icewind\SMB\Options;
use Icewind\SMB\System;
use Icewind\SMB\TimeZoneProvider;
@ -199,8 +199,7 @@ class NotifyHandlerTest extends TestCase {
public function testNoStdBuf(): void {
$this->requireBackendEnv('smbclient');
$this->config = json_decode(file_get_contents(__DIR__ . '/config.json'));
$system = $this->getMockBuilder(System::class)
->onlyMethods(['getStdBufPath'])
$system = $this->getMockBuilder(ISystem::class)
->getMock();
$system->method('getStdBufPath')
->willReturn(null);

View file

@ -9,9 +9,9 @@ namespace Icewind\SMB\Test;
use Icewind\SMB\AnonymousAuth;
use Icewind\SMB\Exception\DependencyException;
use Icewind\SMB\IAuth;
use Icewind\SMB\ISystem;
use Icewind\SMB\Native\NativeServer;
use Icewind\SMB\ServerFactory;
use Icewind\SMB\System;
use Icewind\SMB\Wrapped\Server;
class ServerFactoryTest extends TestCase {
@ -25,13 +25,14 @@ class ServerFactoryTest extends TestCase {
}
public function testSmbClient() {
$this->requireBackendEnv('smbclient');
$system = $this->getMockBuilder(System::class)
->onlyMethods(['libSmbclientAvailable'])
$system = $this->getMockBuilder(ISystem::class)
->getMock();
$system->expects($this->any())
->method('libSmbclientAvailable')
->willReturn(false);
$system->expects($this->any())
->method('getSmbclientPath')
->willReturn("/usr/bin/smbclient");
$factory = new ServerFactory(null, $system);
$this->assertInstanceOf(Server::class, $factory->createServer('localhost', $this->credentials));
}
@ -41,15 +42,19 @@ class ServerFactoryTest extends TestCase {
if (!function_exists('smbclient_state_new')) {
$this->markTestSkipped('libsmbclient php extension not installed');
}
$factory = new ServerFactory();
$system = $this->getMockBuilder(ISystem::class)
->getMock();
$system->expects($this->any())
->method('libSmbclientAvailable')
->willReturn(true);
$factory = new ServerFactory(null, $system);
$this->assertInstanceOf(NativeServer::class, $factory->createServer('localhost', $this->credentials));
}
public function testNoBackend() {
$this->expectException(DependencyException::class);
$this->requireBackendEnv('smbclient');
$system = $this->getMockBuilder(System::class)
->setMethods(['libSmbclientAvailable', 'getSmbclientPath'])
$system = $this->getMockBuilder(ISystem::class)
->getMock();
$system->expects($this->any())
->method('libSmbclientAvailable')

View file

@ -14,7 +14,7 @@ use Icewind\SMB\System;
use Icewind\SMB\TimeZoneProvider;
use Icewind\SMB\Wrapped\Server as NormalServer;
class ShareTest extends AbstractShareTest {
class ShareTest extends AbstractShareTestBase {
public function getServerClass(): string {
$this->requireBackendEnv('smbclient');
return NormalServer::class;

View file

@ -1,7 +1,7 @@
{
"host": "skybox.icewind.link",
"user": "test",
"password": "test",
"share": "test",
"root": "test"
"host": "172.17.0.2",
"user": "test",
"password": "test",
"share": "test",
"root": ""
}

View file

@ -1,17 +0,0 @@
<?php
/**
* SPDX-FileCopyrightText: 2022 Robin Appelman <robin@icewind.nl>
* SPDX-License-Identifier: MIT
*/
class KRB5CCache {
public function getEntries(): array { return [];}
public function getName(): string {return "";}
public function initKeytab(string $principal, string $keytab, array $flags = []): void {}
public function initPassword(string $principal, string $password, array $flags = []): void {}
public function isValid(): bool {return false;}
public function open(string $source): void {}
public function save(string $destination): void {}
public function setConfig(string $destination): void {}
}

View file

@ -1,15 +1,15 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8"?>
<!--
- SPDX-FileCopyrightText: 2012 Robin Appelman <robin@icewind.nl>
- SPDX-License-Identifier: MIT
-->
<phpunit bootstrap="bootstrap.php">
<testsuite name='SMB'>
<directory suffix='.php'>./</directory>
</testsuite>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">../src</directory>
</whitelist>
</filter>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="bootstrap.php" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">../src</directory>
</include>
</coverage>
<testsuite name="SMB">
<directory suffix=".php">./</directory>
</testsuite>
</phpunit>

View file

@ -34,4 +34,4 @@ docker run -d --name apache${FORGEJO_RUN_NUMBER} -v $PWD:/var/www/html -v /tmp/s
APACHE_IP=$(docker inspect apache${FORGEJO_RUN_NUMBER} --format '{{.NetworkSettings.IPAddress}}')
# add the dns record for apache
docker exec dc${FORGEJO_RUN_NUMBER} samba-tool dns add krb.domain.test domain.test httpd A $APACHE_IP -U administrator --password=passwOrd1
docker exec dc${FORGEJO_RUN_NUMBER} samba-tool dns add krb.domain.test domain.test httpd A $APACHE_IP -U administrator --password=passwOrd1

9
tests/start-server.sh Executable file
View file

@ -0,0 +1,9 @@
#!/usr/bin/env bash
#
# SPDX-FileCopyrightText: 2025 Robin Appelman <robin@icewind.nl>
# SPDX-License-Identifier: MIT
#
docker rm -f smb-test
docker run -d --name smb-test -e ACCOUNT_test=test -e UID_test=1000 -e SAMBA_VOLUME_CONFIG_test="[test]; path=/tmp; valid users = test; guest ok = no; read only = no; browseable = yes" servercontainers/samba
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' smb-test