Merge pull request #23359 from owncloud/streams-0.4-9
[9.0] Update icewind/streams and icewind/smb
This commit is contained in:
commit
9b2fdc5358
2
3rdparty
2
3rdparty
|
@ -1 +1 @@
|
|||
Subproject commit 913c4f0028a3bbdf716394c194f3cde8b92f8239
|
||||
Subproject commit afb726b309490ce9df1bd521217da9bbf606593b
|
|
@ -2,3 +2,4 @@ example.php
|
|||
icewind/smb/tests
|
||||
icewind/smb/install_libsmbclient.sh
|
||||
icewind/smb/.travis.yml
|
||||
icewind/streams/tests
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
"classmap-authoritative": true
|
||||
},
|
||||
"require": {
|
||||
"icewind/smb": "1.0.5",
|
||||
"icewind/streams": "0.2"
|
||||
"icewind/smb": "1.0.8",
|
||||
"icewind/streams": "0.4"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,25 +4,25 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "669663944c7232473a1c51a6d160319d",
|
||||
"content-hash": "7612ced4391f6287fb3e50534500d217",
|
||||
"hash": "1671a5ec7bef407432d42775f898dc34",
|
||||
"content-hash": "9d995f0d55bee8a3b344a3c685e7b4a4",
|
||||
"packages": [
|
||||
{
|
||||
"name": "icewind/smb",
|
||||
"version": "v1.0.5",
|
||||
"version": "v1.0.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/icewind1991/SMB.git",
|
||||
"reference": "acb94a0a85290d653cd64c883175b855ada5022f"
|
||||
"reference": "764f3fc793a904eb937d619ad097fb076ff199cd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/icewind1991/SMB/zipball/acb94a0a85290d653cd64c883175b855ada5022f",
|
||||
"reference": "acb94a0a85290d653cd64c883175b855ada5022f",
|
||||
"url": "https://api.github.com/repos/icewind1991/SMB/zipball/764f3fc793a904eb937d619ad097fb076ff199cd",
|
||||
"reference": "764f3fc793a904eb937d619ad097fb076ff199cd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"icewind/streams": "0.2.*",
|
||||
"icewind/streams": ">=0.2.0",
|
||||
"php": ">=5.3"
|
||||
},
|
||||
"require-dev": {
|
||||
|
@ -47,27 +47,28 @@
|
|||
}
|
||||
],
|
||||
"description": "php wrapper for smbclient and libsmbclient-php",
|
||||
"time": "2016-01-20 13:12:36"
|
||||
"time": "2016-03-17 13:29:58"
|
||||
},
|
||||
{
|
||||
"name": "icewind/streams",
|
||||
"version": "0.2",
|
||||
"version": "0.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/icewind1991/Streams.git",
|
||||
"reference": "5aae45f2ddd3d1a6e2a496dd5d1e7857bfeb605a"
|
||||
"reference": "9ca40274645a967ecc3408b0ca2e6255ead1d1d3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/icewind1991/Streams/zipball/5aae45f2ddd3d1a6e2a496dd5d1e7857bfeb605a",
|
||||
"reference": "5aae45f2ddd3d1a6e2a496dd5d1e7857bfeb605a",
|
||||
"url": "https://api.github.com/repos/icewind1991/Streams/zipball/9ca40274645a967ecc3408b0ca2e6255ead1d1d3",
|
||||
"reference": "9ca40274645a967ecc3408b0ca2e6255ead1d1d3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"satooshi/php-coveralls": "dev-master"
|
||||
"phpunit/phpunit": "^4.8",
|
||||
"satooshi/php-coveralls": "v1.0.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
@ -87,7 +88,7 @@
|
|||
}
|
||||
],
|
||||
"description": "A set of generic stream wrappers",
|
||||
"time": "2014-07-30 23:46:15"
|
||||
"time": "2016-03-17 12:32:25"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
|
|
|
@ -13,9 +13,7 @@
|
|||
namespace Composer\Autoload;
|
||||
|
||||
/**
|
||||
* ClassLoader implements a PSR-0 class loader
|
||||
*
|
||||
* See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
|
||||
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||
*
|
||||
* $loader = new \Composer\Autoload\ClassLoader();
|
||||
*
|
||||
|
@ -39,6 +37,8 @@ namespace Composer\Autoload;
|
|||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @see http://www.php-fig.org/psr/psr-0/
|
||||
* @see http://www.php-fig.org/psr/psr-4/
|
||||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
|
@ -147,7 +147,7 @@ class ClassLoader
|
|||
* appending or prepending to the ones previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param array|string $paths The PSR-0 base directories
|
||||
* @param array|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
|
|
|
@ -52,12 +52,23 @@ return array(
|
|||
'Icewind\\SMB\\TimeZoneProvider' => $vendorDir . '/icewind/smb/src/TimeZoneProvider.php',
|
||||
'Icewind\\Streams\\CallbackWrapper' => $vendorDir . '/icewind/streams/src/CallbackWrapper.php',
|
||||
'Icewind\\Streams\\Directory' => $vendorDir . '/icewind/streams/src/Directory.php',
|
||||
'Icewind\\Streams\\DirectoryFilter' => $vendorDir . '/icewind/streams/src/DirectoryFilter.php',
|
||||
'Icewind\\Streams\\DirectoryWrapper' => $vendorDir . '/icewind/streams/src/DirectoryWrapper.php',
|
||||
'Icewind\\Streams\\File' => $vendorDir . '/icewind/streams/src/File.php',
|
||||
'Icewind\\Streams\\IteratorDirectory' => $vendorDir . '/icewind/streams/src/IteratorDirectory.php',
|
||||
'Icewind\\Streams\\NullWrapper' => $vendorDir . '/icewind/streams/src/NullWrapper.php',
|
||||
'Icewind\\Streams\\Tests\\CallbackWrapper' => $vendorDir . '/icewind/streams/tests/CallbackWrapper.php',
|
||||
'Icewind\\Streams\\Tests\\IteratorDirectory' => $vendorDir . '/icewind/streams/tests/IteratorDirectory.php',
|
||||
'Icewind\\Streams\\Tests\\NullWrapper' => $vendorDir . '/icewind/streams/tests/NullWrapper.php',
|
||||
'Icewind\\Streams\\Tests\\Wrapper' => $vendorDir . '/icewind/streams/tests/Wrapper.php',
|
||||
'Icewind\\Streams\\Path' => $vendorDir . '/icewind/streams/src/Path.php',
|
||||
'Icewind\\Streams\\RetryWrapper' => $vendorDir . '/icewind/streams/src/RetryWrapper.php',
|
||||
'Icewind\\Streams\\SeekableWrapper' => $vendorDir . '/icewind/streams/src/SeekableWrapper.php',
|
||||
'Icewind\\Streams\\Tests\\DirectoryFilter' => $vendorDir . '/icewind/streams/tests/DirectoryFilter.php',
|
||||
'Icewind\\Streams\\Tests\\DirectoryWrapper' => $vendorDir . '/icewind/streams/tests/DirectoryWrapper.php',
|
||||
'Icewind\\Streams\\Tests\\DirectoryWrapperDummy' => $vendorDir . '/icewind/streams/tests/DirectoryWrapper.php',
|
||||
'Icewind\\Streams\\Tests\\DirectoryWrapperNull' => $vendorDir . '/icewind/streams/tests/DirectoryWrapper.php',
|
||||
'Icewind\\Streams\\Tests\\PartialWrapper' => $vendorDir . '/icewind/streams/tests/RetryWrapper.php',
|
||||
'Icewind\\Streams\\Tests\\RetryWrapper' => $vendorDir . '/icewind/streams/tests/RetryWrapper.php',
|
||||
'Icewind\\Streams\\Tests\\SeekableWrapper' => $vendorDir . '/icewind/streams/tests/SeekableWrapper.php',
|
||||
'Icewind\\Streams\\Tests\\UrlCallBack' => $vendorDir . '/icewind/streams/tests/UrlCallBack.php',
|
||||
'Icewind\\Streams\\Url' => $vendorDir . '/icewind/streams/src/Url.php',
|
||||
'Icewind\\Streams\\UrlCallback' => $vendorDir . '/icewind/streams/src/UrlCallBack.php',
|
||||
'Icewind\\Streams\\Wrapper' => $vendorDir . '/icewind/streams/src/Wrapper.php',
|
||||
);
|
||||
|
|
|
@ -23,16 +23,6 @@ class ComposerAutoloaderInit98fe9b281934250b3a93f69a5ce843b3
|
|||
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit98fe9b281934250b3a93f69a5ce843b3', 'loadClassLoader'));
|
||||
|
||||
$map = require __DIR__ . '/autoload_namespaces.php';
|
||||
foreach ($map as $namespace => $path) {
|
||||
$loader->set($namespace, $path);
|
||||
}
|
||||
|
||||
$map = require __DIR__ . '/autoload_psr4.php';
|
||||
foreach ($map as $namespace => $path) {
|
||||
$loader->setPsr4($namespace, $path);
|
||||
}
|
||||
|
||||
$classMap = require __DIR__ . '/autoload_classmap.php';
|
||||
if ($classMap) {
|
||||
$loader->addClassMap($classMap);
|
||||
|
@ -44,8 +34,3 @@ class ComposerAutoloaderInit98fe9b281934250b3a93f69a5ce843b3
|
|||
return $loader;
|
||||
}
|
||||
}
|
||||
|
||||
function composerRequire98fe9b281934250b3a93f69a5ce843b3($file)
|
||||
{
|
||||
require $file;
|
||||
}
|
||||
|
|
|
@ -1,26 +1,27 @@
|
|||
[
|
||||
{
|
||||
"name": "icewind/streams",
|
||||
"version": "0.2",
|
||||
"version_normalized": "0.2.0.0",
|
||||
"version": "0.4.0",
|
||||
"version_normalized": "0.4.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/icewind1991/Streams.git",
|
||||
"reference": "5aae45f2ddd3d1a6e2a496dd5d1e7857bfeb605a"
|
||||
"reference": "9ca40274645a967ecc3408b0ca2e6255ead1d1d3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/icewind1991/Streams/zipball/5aae45f2ddd3d1a6e2a496dd5d1e7857bfeb605a",
|
||||
"reference": "5aae45f2ddd3d1a6e2a496dd5d1e7857bfeb605a",
|
||||
"url": "https://api.github.com/repos/icewind1991/Streams/zipball/9ca40274645a967ecc3408b0ca2e6255ead1d1d3",
|
||||
"reference": "9ca40274645a967ecc3408b0ca2e6255ead1d1d3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"satooshi/php-coveralls": "dev-master"
|
||||
"phpunit/phpunit": "^4.8",
|
||||
"satooshi/php-coveralls": "v1.0.0"
|
||||
},
|
||||
"time": "2014-07-30 23:46:15",
|
||||
"time": "2016-03-17 12:32:25",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
|
@ -43,28 +44,28 @@
|
|||
},
|
||||
{
|
||||
"name": "icewind/smb",
|
||||
"version": "v1.0.5",
|
||||
"version_normalized": "1.0.5.0",
|
||||
"version": "v1.0.8",
|
||||
"version_normalized": "1.0.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/icewind1991/SMB.git",
|
||||
"reference": "acb94a0a85290d653cd64c883175b855ada5022f"
|
||||
"reference": "764f3fc793a904eb937d619ad097fb076ff199cd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/icewind1991/SMB/zipball/acb94a0a85290d653cd64c883175b855ada5022f",
|
||||
"reference": "acb94a0a85290d653cd64c883175b855ada5022f",
|
||||
"url": "https://api.github.com/repos/icewind1991/SMB/zipball/764f3fc793a904eb937d619ad097fb076ff199cd",
|
||||
"reference": "764f3fc793a904eb937d619ad097fb076ff199cd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"icewind/streams": "0.2.*",
|
||||
"icewind/streams": ">=0.2.0",
|
||||
"php": ">=5.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8",
|
||||
"satooshi/php-coveralls": "v1.0.0"
|
||||
},
|
||||
"time": "2016-01-20 13:12:36",
|
||||
"time": "2016-03-17 13:29:58",
|
||||
"type": "library",
|
||||
"installation-source": "source",
|
||||
"autoload": {
|
||||
|
|
|
@ -75,7 +75,7 @@ $share = $server->getShare('test');
|
|||
$content = $share->dir('test');
|
||||
|
||||
foreach ($content as $info) {
|
||||
echo $name->getName() . "\n";
|
||||
echo $info->getName() . "\n";
|
||||
echo "\tsize :" . $info->getSize() . "\n";
|
||||
}
|
||||
```
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
],
|
||||
"require" : {
|
||||
"php": ">=5.3",
|
||||
"icewind/streams": "0.2.*"
|
||||
"icewind/streams": ">=0.2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"satooshi/php-coveralls" : "v1.0.0",
|
||||
|
|
|
@ -239,8 +239,9 @@ class NativeShare extends AbstractShare {
|
|||
*/
|
||||
public function read($source) {
|
||||
$this->connect();
|
||||
$handle = $this->state->open($this->buildUrl($source), 'r');
|
||||
return NativeStream::wrap($this->state, $handle, 'r');
|
||||
$url = $this->buildUrl($source);
|
||||
$handle = $this->state->open($url, 'r');
|
||||
return NativeStream::wrap($this->state, $handle, 'r', $url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -254,8 +255,9 @@ class NativeShare extends AbstractShare {
|
|||
*/
|
||||
public function write($source) {
|
||||
$this->connect();
|
||||
$handle = $this->state->create($this->buildUrl($source));
|
||||
return NativeStream::wrap($this->state, $handle, 'w');
|
||||
$url = $this->buildUrl($source);
|
||||
$handle = $this->state->create($url);
|
||||
return NativeStream::wrap($this->state, $handle, 'w', $url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
namespace Icewind\SMB;
|
||||
|
||||
use Icewind\SMB\Exception\Exception;
|
||||
use Icewind\SMB\Exception\InvalidRequestException;
|
||||
use Icewind\Streams\File;
|
||||
|
||||
|
@ -31,20 +32,27 @@ class NativeStream implements File {
|
|||
*/
|
||||
private $eof = false;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $url;
|
||||
|
||||
/**
|
||||
* Wrap a stream from libsmbclient-php into a regular php stream
|
||||
*
|
||||
* @param \Icewind\SMB\NativeState $state
|
||||
* @param resource $smbStream
|
||||
* @param string $mode
|
||||
* @param string $url
|
||||
* @return resource
|
||||
*/
|
||||
public static function wrap($state, $smbStream, $mode) {
|
||||
public static function wrap($state, $smbStream, $mode, $url) {
|
||||
stream_wrapper_register('nativesmb', '\Icewind\SMB\NativeStream');
|
||||
$context = stream_context_create(array(
|
||||
'nativesmb' => array(
|
||||
'state' => $state,
|
||||
'handle' => $smbStream
|
||||
'handle' => $smbStream,
|
||||
'url' => $url
|
||||
)
|
||||
));
|
||||
$fh = fopen('nativesmb://', $mode, false, $context);
|
||||
|
@ -68,6 +76,7 @@ class NativeStream implements File {
|
|||
$context = stream_context_get_options($this->context);
|
||||
$this->state = $context['nativesmb']['state'];
|
||||
$this->handle = $context['nativesmb']['handle'];
|
||||
$this->url = $context['nativesmb']['url'];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -89,7 +98,11 @@ class NativeStream implements File {
|
|||
}
|
||||
|
||||
public function stream_stat() {
|
||||
return $this->state->fstat($this->handle);
|
||||
try {
|
||||
return $this->state->stat($this->url);
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function stream_tell() {
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"name": "icewind/streams-dummy",
|
||||
"provide": {
|
||||
"icewind/streams": "0.2"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,14 @@
|
|||
language: php
|
||||
php:
|
||||
- 5.3
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
- 7.0
|
||||
- hhvm
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- php: hhvm # due to facebook/hhvm#3321
|
||||
allow_failures:
|
||||
- php: hhvm # due to facebook/hhvm#3321
|
||||
|
||||
env:
|
||||
global:
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Robin Appelman
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
[![Build Status](https://travis-ci.org/icewind1991/Streams.svg?branch=master)](https://travis-ci.org/icewind1991/Streams)
|
||||
[![Coverage Status](https://img.shields.io/coveralls/icewind1991/Streams.svg)](https://coveralls.io/r/icewind1991/Streams?branch=master)
|
||||
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/icewind1991/Streams/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/icewind1991/Streams/?branch=master)
|
||||
|
||||
Generic stream wrappers for php.
|
||||
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
"php": ">=5.3"
|
||||
},
|
||||
"require-dev" : {
|
||||
"satooshi/php-coveralls": "dev-master"
|
||||
"satooshi/php-coveralls": "v1.0.0",
|
||||
"phpunit/phpunit": "^4.8"
|
||||
},
|
||||
"autoload" : {
|
||||
"psr-4": {
|
||||
|
|
|
@ -13,10 +13,11 @@ namespace Icewind\Streams;
|
|||
* The following options should be passed in the context when opening the stream
|
||||
* [
|
||||
* 'callback' => [
|
||||
* 'source' => resource
|
||||
* 'read' => function($count){} (optional)
|
||||
* 'write' => function($data){} (optional)
|
||||
* 'close' => function(){} (optional)
|
||||
* 'source' => resource
|
||||
* 'read' => function($count){} (optional)
|
||||
* 'write' => function($data){} (optional)
|
||||
* 'close' => function(){} (optional)
|
||||
* 'readdir' => function(){} (optional)
|
||||
* ]
|
||||
* ]
|
||||
*
|
||||
|
@ -38,6 +39,11 @@ class CallbackWrapper extends Wrapper {
|
|||
*/
|
||||
protected $closeCallback;
|
||||
|
||||
/**
|
||||
* @var callable
|
||||
*/
|
||||
protected $readDirCallBack;
|
||||
|
||||
/**
|
||||
* Wraps a stream with the provided callbacks
|
||||
*
|
||||
|
@ -45,48 +51,45 @@ class CallbackWrapper extends Wrapper {
|
|||
* @param callable $read (optional)
|
||||
* @param callable $write (optional)
|
||||
* @param callable $close (optional)
|
||||
* @param callable $readDir (optional)
|
||||
* @return resource
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*/
|
||||
public static function wrap($source, $read = null, $write = null, $close = null) {
|
||||
public static function wrap($source, $read = null, $write = null, $close = null, $readDir = null) {
|
||||
$context = stream_context_create(array(
|
||||
'callback' => array(
|
||||
'source' => $source,
|
||||
'read' => $read,
|
||||
'write' => $write,
|
||||
'close' => $close
|
||||
'close' => $close,
|
||||
'readDir' => $readDir
|
||||
)
|
||||
));
|
||||
stream_wrapper_register('callback', '\Icewind\Streams\CallbackWrapper');
|
||||
try {
|
||||
$wrapped = fopen('callback://', 'r+', false, $context);
|
||||
} catch (\BadMethodCallException $e) {
|
||||
stream_wrapper_unregister('callback');
|
||||
throw $e;
|
||||
}
|
||||
stream_wrapper_unregister('callback');
|
||||
return $wrapped;
|
||||
return Wrapper::wrapSource($source, $context, 'callback', '\Icewind\Streams\CallbackWrapper');
|
||||
}
|
||||
|
||||
protected function open() {
|
||||
$context = $this->loadContext('callback');
|
||||
|
||||
$this->readCallback = $context['read'];
|
||||
$this->writeCallback = $context['write'];
|
||||
$this->closeCallback = $context['close'];
|
||||
$this->readDirCallBack = $context['readDir'];
|
||||
return true;
|
||||
}
|
||||
|
||||
public function dir_opendir($path, $options) {
|
||||
return $this->open();
|
||||
}
|
||||
|
||||
public function stream_open($path, $mode, $options, &$opened_path) {
|
||||
$context = $this->loadContext('callback');
|
||||
|
||||
if (isset($context['read']) and is_callable($context['read'])) {
|
||||
$this->readCallback = $context['read'];
|
||||
}
|
||||
if (isset($context['write']) and is_callable($context['write'])) {
|
||||
$this->writeCallback = $context['write'];
|
||||
}
|
||||
if (isset($context['close']) and is_callable($context['close'])) {
|
||||
$this->closeCallback = $context['close'];
|
||||
}
|
||||
return true;
|
||||
return $this->open();
|
||||
}
|
||||
|
||||
public function stream_read($count) {
|
||||
$result = parent::stream_read($count);
|
||||
if ($this->readCallback) {
|
||||
if (is_callable($this->readCallback)) {
|
||||
call_user_func($this->readCallback, $count);
|
||||
}
|
||||
return $result;
|
||||
|
@ -94,7 +97,7 @@ class CallbackWrapper extends Wrapper {
|
|||
|
||||
public function stream_write($data) {
|
||||
$result = parent::stream_write($data);
|
||||
if ($this->writeCallback) {
|
||||
if (is_callable($this->writeCallback)) {
|
||||
call_user_func($this->writeCallback, $data);
|
||||
}
|
||||
return $result;
|
||||
|
@ -102,9 +105,17 @@ class CallbackWrapper extends Wrapper {
|
|||
|
||||
public function stream_close() {
|
||||
$result = parent::stream_close();
|
||||
if ($this->closeCallback) {
|
||||
if (is_callable($this->closeCallback)) {
|
||||
call_user_func($this->closeCallback);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function dir_readdir() {
|
||||
$result = parent::dir_readdir();
|
||||
if (is_callable($this->readDirCallBack)) {
|
||||
call_user_func($this->readDirCallBack);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
/**
|
||||
* Copyright (c) 2015 Robin Appelman <icewind@owncloud.com>
|
||||
* This file is licensed under the Licensed under the MIT license:
|
||||
* http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Icewind\Streams;
|
||||
|
||||
/**
|
||||
* Wrapper allows filtering of directories
|
||||
*
|
||||
* The filter callback will be called for each entry in the folder
|
||||
* when the callback return false the entry will be filtered out
|
||||
*/
|
||||
class DirectoryFilter extends DirectoryWrapper {
|
||||
/**
|
||||
* @var callable
|
||||
*/
|
||||
private $filter;
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param array $options
|
||||
* @return bool
|
||||
*/
|
||||
public function dir_opendir($path, $options) {
|
||||
$context = $this->loadContext('filter');
|
||||
$this->filter = $context['filter'];
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function dir_readdir() {
|
||||
$file = readdir($this->source);
|
||||
$filter = $this->filter;
|
||||
// keep reading untill we have an accepted entry or we're at the end of the folder
|
||||
while ($file !== false && $filter($file) === false) {
|
||||
$file = readdir($this->source);
|
||||
}
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param resource $source
|
||||
* @param callable $filter
|
||||
* @return resource
|
||||
*/
|
||||
public static function wrap($source, callable $filter) {
|
||||
$options = array(
|
||||
'filter' => array(
|
||||
'source' => $source,
|
||||
'filter' => $filter
|
||||
)
|
||||
);
|
||||
return self::wrapWithOptions($options, '\Icewind\Streams\DirectoryFilter');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
/**
|
||||
* Copyright (c) 2015 Robin Appelman <icewind@owncloud.com>
|
||||
* This file is licensed under the Licensed under the MIT license:
|
||||
* http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Icewind\Streams;
|
||||
|
||||
class DirectoryWrapper implements Directory {
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
public $context;
|
||||
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
protected $source;
|
||||
|
||||
/**
|
||||
* Load the source from the stream context and return the context options
|
||||
*
|
||||
* @param string $name
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function loadContext($name) {
|
||||
$context = stream_context_get_options($this->context);
|
||||
if (isset($context[$name])) {
|
||||
$context = $context[$name];
|
||||
} else {
|
||||
throw new \BadMethodCallException('Invalid context, "' . $name . '" options not set');
|
||||
}
|
||||
if (isset($context['source']) and is_resource($context['source'])) {
|
||||
$this->source = $context['source'];
|
||||
} else {
|
||||
throw new \BadMethodCallException('Invalid context, source not set');
|
||||
}
|
||||
return $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param array $options
|
||||
* @return bool
|
||||
*/
|
||||
public function dir_opendir($path, $options) {
|
||||
$this->loadContext('dir');
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function dir_readdir() {
|
||||
return readdir($this->source);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function dir_closedir() {
|
||||
closedir($this->source);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function dir_rewinddir() {
|
||||
rewinddir($this->source);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options the options for the context to wrap the stream with
|
||||
* @param string $class
|
||||
* @return resource
|
||||
*/
|
||||
protected static function wrapWithOptions($options, $class) {
|
||||
$context = stream_context_create($options);
|
||||
stream_wrapper_register('dirwrapper', $class);
|
||||
$wrapped = opendir('dirwrapper://', $context);
|
||||
stream_wrapper_unregister('dirwrapper');
|
||||
return $wrapped;
|
||||
}
|
||||
}
|
|
@ -21,7 +21,7 @@ interface File {
|
|||
public function stream_open($path, $mode, $options, &$opened_path);
|
||||
|
||||
/**
|
||||
* @param string $offset
|
||||
* @param int $offset
|
||||
* @param int $whence
|
||||
* @return bool
|
||||
*/
|
||||
|
|
|
@ -45,9 +45,9 @@ class IteratorDirectory implements Directory {
|
|||
} else {
|
||||
throw new \BadMethodCallException('Invalid context, "' . $name . '" options not set');
|
||||
}
|
||||
if (isset($context['iterator']) and $context['iterator'] instanceof \Iterator) {
|
||||
if (isset($context['iterator'])) {
|
||||
$this->iterator = $context['iterator'];
|
||||
} else if (isset($context['array']) and is_array($context['array'])) {
|
||||
} else if (isset($context['array'])) {
|
||||
$this->iterator = new \ArrayIterator($context['array']);
|
||||
} else {
|
||||
throw new \BadMethodCallException('Invalid context, iterator or array not set');
|
||||
|
|
|
@ -24,19 +24,16 @@ class NullWrapper extends Wrapper {
|
|||
'null' => array(
|
||||
'source' => $source)
|
||||
));
|
||||
stream_wrapper_register('null', '\Icewind\Streams\NullWrapper');
|
||||
try {
|
||||
$wrapped = fopen('null://', 'r+', false, $context);
|
||||
} catch (\BadMethodCallException $e) {
|
||||
stream_wrapper_unregister('null');
|
||||
throw $e;
|
||||
}
|
||||
stream_wrapper_unregister('null');
|
||||
return $wrapped;
|
||||
return Wrapper::wrapSource($source, $context, 'null', '\Icewind\Streams\NullWrapper');
|
||||
}
|
||||
|
||||
public function stream_open($path, $mode, $options, &$opened_path) {
|
||||
$this->loadContext('null');
|
||||
return true;
|
||||
}
|
||||
|
||||
public function dir_opendir($path, $options) {
|
||||
$this->loadContext('null');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
<?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\Streams;
|
||||
|
||||
/**
|
||||
* A string-like object that automatically registers a stream wrapper when used and removes the stream wrapper when no longer used
|
||||
*
|
||||
* Can optionally pass context options to the stream wrapper
|
||||
*/
|
||||
class Path {
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $registered = false;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $protocol;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $class;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $contextOptions;
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param array $contextOptions
|
||||
*/
|
||||
public function __construct($class, $contextOptions = array()) {
|
||||
$this->class = $class;
|
||||
$this->contextOptions = $contextOptions;
|
||||
}
|
||||
|
||||
public function getProtocol() {
|
||||
if (!$this->protocol) {
|
||||
$this->protocol = 'auto' . uniqid();
|
||||
}
|
||||
return $this->protocol;
|
||||
}
|
||||
|
||||
public function wrapPath($path) {
|
||||
return $this->getProtocol() . '://' . $path;
|
||||
}
|
||||
|
||||
protected function register() {
|
||||
if (!$this->registered) {
|
||||
$this->appendDefaultContent($this->getProtocol(), $this->contextOptions);
|
||||
stream_wrapper_register($this->getProtocol(), $this->class);
|
||||
$this->registered = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected function unregister() {
|
||||
stream_wrapper_unregister($this->getProtocol());
|
||||
$this->unsetDefaultContent($this->getProtocol());
|
||||
$this->registered = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add values to the default stream context
|
||||
*
|
||||
* @param string $key
|
||||
* @param array $values
|
||||
*/
|
||||
protected function appendDefaultContent($key, $values) {
|
||||
$context = stream_context_get_default();
|
||||
$defaults = stream_context_get_options($context);
|
||||
$defaults[$key] = $values;
|
||||
stream_context_set_default($defaults);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove values from the default stream context
|
||||
*
|
||||
* @param string $key
|
||||
*/
|
||||
protected function unsetDefaultContent($key) {
|
||||
$context = stream_context_get_default();
|
||||
$defaults = stream_context_get_options($context);
|
||||
unset($defaults[$key]);
|
||||
stream_context_set_default($defaults);
|
||||
}
|
||||
|
||||
public function __toString() {
|
||||
$this->register();
|
||||
return $this->protocol . '://';
|
||||
}
|
||||
|
||||
public function __destruct() {
|
||||
$this->unregister();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
/**
|
||||
* Copyright (c) 2016 Robin Appelman <icewind@owncloud.com>
|
||||
* This file is licensed under the Licensed under the MIT license:
|
||||
* http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Icewind\Streams;
|
||||
|
||||
/**
|
||||
* Wrapper that retries reads/writes to remote streams that dont deliver/recieve all requested data at once
|
||||
*/
|
||||
class RetryWrapper extends Wrapper {
|
||||
|
||||
/**
|
||||
* Wraps a stream with the provided callbacks
|
||||
*
|
||||
* @param resource $source
|
||||
* @return resource
|
||||
*/
|
||||
public static function wrap($source) {
|
||||
$context = stream_context_create(array(
|
||||
'retry' => array(
|
||||
'source' => $source
|
||||
)
|
||||
));
|
||||
return Wrapper::wrapSource($source, $context, 'retry', '\Icewind\Streams\RetryWrapper');
|
||||
}
|
||||
|
||||
protected function open() {
|
||||
$this->loadContext('retry');
|
||||
return true;
|
||||
}
|
||||
|
||||
public function dir_opendir($path, $options) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function stream_open($path, $mode, $options, &$opened_path) {
|
||||
return $this->open();
|
||||
}
|
||||
|
||||
public function stream_read($count) {
|
||||
$result = parent::stream_read($count);
|
||||
|
||||
$bytesReceived = strlen($result);
|
||||
while ($bytesReceived < $count && !$this->stream_eof()) {
|
||||
$result .= parent::stream_read($count - $bytesReceived);
|
||||
$bytesReceived = strlen($result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function stream_write($data) {
|
||||
$bytesToSend = strlen($data);
|
||||
$result = parent::stream_write($data);
|
||||
|
||||
while ($result < $bytesToSend && !$this->stream_eof()) {
|
||||
$dataLeft = substr($data, $result);
|
||||
$result += parent::stream_write($dataLeft);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
<?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\Streams;
|
||||
|
||||
/**
|
||||
* Wrapper that provides callbacks for write, read and close
|
||||
*
|
||||
* The following options should be passed in the context when opening the stream
|
||||
* [
|
||||
* 'callback' => [
|
||||
* 'source' => resource
|
||||
* ]
|
||||
* ]
|
||||
*
|
||||
* All callbacks are called after the operation is executed on the source stream
|
||||
*/
|
||||
class SeekableWrapper extends Wrapper {
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* Wraps a stream to make it seekable
|
||||
*
|
||||
* @param resource $source
|
||||
* @return resource
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*/
|
||||
public static function wrap($source) {
|
||||
$context = stream_context_create(array(
|
||||
'callback' => array(
|
||||
'source' => $source
|
||||
)
|
||||
));
|
||||
return Wrapper::wrapSource($source, $context, 'callback', '\Icewind\Streams\SeekableWrapper');
|
||||
}
|
||||
|
||||
public function dir_opendir($path, $options) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function stream_open($path, $mode, $options, &$opened_path) {
|
||||
$this->loadContext('callback');
|
||||
$this->cache = fopen('php://temp', 'w+');
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function readTill($position) {
|
||||
$current = ftell($this->source);
|
||||
if ($position > $current) {
|
||||
$data = parent::stream_read($position - $current);
|
||||
$cachePosition = ftell($this->cache);
|
||||
fseek($this->cache, $current);
|
||||
fwrite($this->cache, $data);
|
||||
fseek($this->cache, $cachePosition);
|
||||
}
|
||||
}
|
||||
|
||||
public function stream_read($count) {
|
||||
$current = ftell($this->cache);
|
||||
$this->readTill($current + $count);
|
||||
return fread($this->cache, $count);
|
||||
}
|
||||
|
||||
public function stream_seek($offset, $whence = SEEK_SET) {
|
||||
if ($whence === SEEK_SET) {
|
||||
$target = $offset;
|
||||
} else if ($whence === SEEK_CUR) {
|
||||
$current = ftell($this->cache);
|
||||
$target = $current + $offset;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
$this->readTill($target);
|
||||
return fseek($this->cache, $target) === 0;
|
||||
}
|
||||
|
||||
public function stream_tell() {
|
||||
return ftell($this->cache);
|
||||
}
|
||||
|
||||
public function stream_eof() {
|
||||
return parent::stream_eof() and (ftell($this->source) === ftell($this->cache));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
<?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\Streams;
|
||||
|
||||
/**
|
||||
* Interface for stream wrappers that implement url functions such as unlink, stat
|
||||
*/
|
||||
interface Url {
|
||||
/**
|
||||
* @param string $path
|
||||
* @param array $options
|
||||
* @return bool
|
||||
*/
|
||||
public function dir_opendir($path, $options);
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param string $mode
|
||||
* @param int $options
|
||||
* @param string &$opened_path
|
||||
* @return bool
|
||||
*/
|
||||
public function stream_open($path, $mode, $options, &$opened_path);
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param int $mode
|
||||
* @param int $options
|
||||
* @return bool
|
||||
*/
|
||||
public function mkdir($path, $mode, $options);
|
||||
|
||||
/**
|
||||
* @param string $source
|
||||
* @param string $target
|
||||
* @return bool
|
||||
*/
|
||||
public function rename($source, $target);
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param int $options
|
||||
* @return bool
|
||||
*/
|
||||
public function rmdir($path, $options);
|
||||
|
||||
/**
|
||||
* @param string
|
||||
* @return bool
|
||||
*/
|
||||
public function unlink($path);
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param int $flags
|
||||
* @return array
|
||||
*/
|
||||
public function url_stat($path, $flags);
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
<?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\Streams;
|
||||
|
||||
/**
|
||||
* Wrapper that provides callbacks for url actions such as fopen, unlink, rename
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* $path = UrlCallBack('/path/so/source', function(){
|
||||
* echo 'fopen';
|
||||
* }, function(){
|
||||
* echo 'opendir';
|
||||
* }, function(){
|
||||
* echo 'mkdir';
|
||||
* }, function(){
|
||||
* echo 'rename';
|
||||
* }, function(){
|
||||
* echo 'rmdir';
|
||||
* }, function(){
|
||||
* echo 'unlink';
|
||||
* }, function(){
|
||||
* echo 'stat';
|
||||
* });
|
||||
*
|
||||
* mkdir($path);
|
||||
* ...
|
||||
*
|
||||
* All callbacks are called after the operation is executed on the source stream
|
||||
*/
|
||||
class UrlCallback extends Wrapper implements Url {
|
||||
|
||||
/**
|
||||
* @param string $source
|
||||
* @param callable $fopen
|
||||
* @param callable $opendir
|
||||
* @param callable $mkdir
|
||||
* @param callable $rename
|
||||
* @param callable $rmdir
|
||||
* @param callable $unlink
|
||||
* @param callable $stat
|
||||
* @return \Icewind\Streams\Path
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function wrap($source, $fopen = null, $opendir = null, $mkdir = null, $rename = null, $rmdir = null,
|
||||
$unlink = null, $stat = null) {
|
||||
$options = array(
|
||||
'source' => $source,
|
||||
'fopen' => $fopen,
|
||||
'opendir' => $opendir,
|
||||
'mkdir' => $mkdir,
|
||||
'rename' => $rename,
|
||||
'rmdir' => $rmdir,
|
||||
'unlink' => $unlink,
|
||||
'stat' => $stat
|
||||
);
|
||||
return new Path('\Icewind\Streams\UrlCallBack', $options);
|
||||
}
|
||||
|
||||
protected function loadContext($url) {
|
||||
list($protocol) = explode('://', $url);
|
||||
$options = stream_context_get_options($this->context);
|
||||
return $options[$protocol];
|
||||
}
|
||||
|
||||
protected function callCallBack($context, $callback) {
|
||||
if (is_callable($context[$callback])) {
|
||||
call_user_func($context[$callback]);
|
||||
}
|
||||
}
|
||||
|
||||
public function stream_open($path, $mode, $options, &$opened_path) {
|
||||
$context = $this->loadContext($path);
|
||||
$this->callCallBack($context, 'fopen');
|
||||
$this->setSourceStream(fopen($context['source'], $mode));
|
||||
return true;
|
||||
}
|
||||
|
||||
public function dir_opendir($path, $options) {
|
||||
$context = $this->loadContext($path);
|
||||
$this->callCallBack($context, 'opendir');
|
||||
$this->setSourceStream(opendir($context['source']));
|
||||
return true;
|
||||
}
|
||||
|
||||
public function mkdir($path, $mode, $options) {
|
||||
$context = $this->loadContext($path);
|
||||
$this->callCallBack($context, 'mkdir');
|
||||
return mkdir($context['source'], $mode, $options & STREAM_MKDIR_RECURSIVE);
|
||||
}
|
||||
|
||||
public function rmdir($path, $options) {
|
||||
$context = $this->loadContext($path);
|
||||
$this->callCallBack($context, 'rmdir');
|
||||
return rmdir($context['source']);
|
||||
}
|
||||
|
||||
public function rename($source, $target) {
|
||||
$context = $this->loadContext($source);
|
||||
$this->callCallBack($context, 'rename');
|
||||
list(, $target) = explode('://', $target);
|
||||
return rename($context['source'], $target);
|
||||
}
|
||||
|
||||
public function unlink($path) {
|
||||
$context = $this->loadContext($path);
|
||||
$this->callCallBack($context, 'unlink');
|
||||
return unlink($context['source']);
|
||||
}
|
||||
|
||||
public function url_stat($path, $flags) {
|
||||
throw new \Exception('stat is not supported due to php bug 50526');
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ namespace Icewind\Streams;
|
|||
*
|
||||
* This wrapper itself doesn't implement any functionality but is just a base class for other wrappers to extend
|
||||
*/
|
||||
abstract class Wrapper implements File {
|
||||
abstract class Wrapper implements File, Directory {
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
|
@ -25,6 +25,22 @@ abstract class Wrapper implements File {
|
|||
*/
|
||||
protected $source;
|
||||
|
||||
protected static function wrapSource($source, $context, $protocol, $class) {
|
||||
try {
|
||||
stream_wrapper_register($protocol, $class);
|
||||
if (@rewinddir($source) === false) {
|
||||
$wrapped = fopen($protocol . '://', 'r+', false, $context);
|
||||
} else {
|
||||
$wrapped = opendir($protocol . '://', $context);
|
||||
}
|
||||
} catch (\BadMethodCallException $e) {
|
||||
stream_wrapper_unregister($protocol);
|
||||
throw $e;
|
||||
}
|
||||
stream_wrapper_unregister($protocol);
|
||||
return $wrapped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the source from the stream context and return the context options
|
||||
*
|
||||
|
@ -107,4 +123,17 @@ abstract class Wrapper implements File {
|
|||
public function stream_close() {
|
||||
return fclose($this->source);
|
||||
}
|
||||
|
||||
public function dir_readdir() {
|
||||
return readdir($this->source);
|
||||
}
|
||||
|
||||
public function dir_closedir() {
|
||||
closedir($this->source);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function dir_rewinddir() {
|
||||
return rewind($this->source);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,72 +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\Streams\Tests;
|
||||
|
||||
class CallbackWrapper extends Wrapper {
|
||||
|
||||
/**
|
||||
* @param resource $source
|
||||
* @param callable $read
|
||||
* @param callable $write
|
||||
* @param callable $close
|
||||
* @return resource
|
||||
*/
|
||||
protected function wrapSource($source, $read = null, $write = null, $close = null) {
|
||||
return \Icewind\Streams\CallbackWrapper::wrap($source, $read, $write, $close);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \BadMethodCallException
|
||||
*/
|
||||
public function testWrapInvalidSource() {
|
||||
$this->wrapSource('foo');
|
||||
}
|
||||
|
||||
public function testReadCallback() {
|
||||
$called = false;
|
||||
$callBack = function () use (&$called) {
|
||||
$called = true;
|
||||
};
|
||||
|
||||
$source = fopen('php://temp', 'r+');
|
||||
fwrite($source, 'foobar');
|
||||
rewind($source);
|
||||
|
||||
$wrapped = $this->wrapSource($source, $callBack);
|
||||
$this->assertEquals('foo', fread($wrapped, 3));
|
||||
$this->assertTrue($called);
|
||||
}
|
||||
|
||||
public function testWriteCallback() {
|
||||
$lastData = '';
|
||||
$callBack = function ($data) use (&$lastData) {
|
||||
$lastData = $data;
|
||||
};
|
||||
|
||||
$source = fopen('php://temp', 'r+');
|
||||
|
||||
$wrapped = $this->wrapSource($source, null, $callBack);
|
||||
fwrite($wrapped, 'foobar');
|
||||
$this->assertEquals('foobar', $lastData);
|
||||
}
|
||||
|
||||
public function testCloseCallback() {
|
||||
$called = false;
|
||||
$callBack = function () use (&$called) {
|
||||
$called = true;
|
||||
};
|
||||
|
||||
$source = fopen('php://temp', 'r+');
|
||||
fwrite($source, 'foobar');
|
||||
rewind($source);
|
||||
|
||||
$wrapped = $this->wrapSource($source, null, null, $callBack);
|
||||
fclose($wrapped);
|
||||
$this->assertTrue($called);
|
||||
}
|
||||
}
|
|
@ -1,130 +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\Streams\Tests;
|
||||
|
||||
class IteratorDirectory extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
/**
|
||||
* @param \Iterator | array $source
|
||||
* @return resource
|
||||
*/
|
||||
protected function wrapSource($source) {
|
||||
return \Icewind\Streams\IteratorDirectory::wrap($source);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \BadMethodCallException
|
||||
*/
|
||||
public function testNoContext() {
|
||||
$context = stream_context_create(array());
|
||||
stream_wrapper_register('iterator', '\Icewind\Streams\IteratorDirectory');
|
||||
try {
|
||||
opendir('iterator://', $context);
|
||||
stream_wrapper_unregister('iterator');
|
||||
} catch (\Exception $e) {
|
||||
stream_wrapper_unregister('iterator');
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \BadMethodCallException
|
||||
*/
|
||||
public function testInvalidSource() {
|
||||
$context = stream_context_create(array(
|
||||
'dir' => array(
|
||||
'array' => 2
|
||||
)
|
||||
));
|
||||
stream_wrapper_register('iterator', '\Icewind\Streams\IteratorDirectory');
|
||||
try {
|
||||
opendir('iterator://', $context);
|
||||
stream_wrapper_unregister('iterator');
|
||||
} catch (\Exception $e) {
|
||||
stream_wrapper_unregister('iterator');
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \BadMethodCallException
|
||||
*/
|
||||
public function testWrapInvalidSource() {
|
||||
$this->wrapSource(2);
|
||||
}
|
||||
|
||||
public function fileListProvider() {
|
||||
$longList = array_fill(0, 500, 'foo');
|
||||
return array(
|
||||
array(
|
||||
array(
|
||||
'foo',
|
||||
'bar',
|
||||
'qwerty'
|
||||
)
|
||||
),
|
||||
array(
|
||||
array(
|
||||
'with spaces',
|
||||
'under_scores',
|
||||
'日本語',
|
||||
'character %$_',
|
||||
'.',
|
||||
'0',
|
||||
'double "quotes"',
|
||||
"single 'quotes'"
|
||||
)
|
||||
),
|
||||
array(
|
||||
array(
|
||||
'single item'
|
||||
)
|
||||
),
|
||||
array(
|
||||
$longList
|
||||
),
|
||||
array(
|
||||
array()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
protected function basicTest($fileList, $dh) {
|
||||
$result = array();
|
||||
|
||||
while (($file = readdir($dh)) !== false) {
|
||||
$result[] = $file;
|
||||
}
|
||||
|
||||
$this->assertEquals($fileList, $result);
|
||||
|
||||
rewinddir($dh);
|
||||
if (count($fileList)) {
|
||||
$this->assertEquals($fileList[0], readdir($dh));
|
||||
} else {
|
||||
$this->assertFalse(readdir($dh));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider fileListProvider
|
||||
*/
|
||||
public function testBasicIterator($fileList) {
|
||||
$iterator = new \ArrayIterator($fileList);
|
||||
$dh = $this->wrapSource($iterator);
|
||||
$this->basicTest($fileList, $dh);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider fileListProvider
|
||||
*/
|
||||
public function testBasicArray($fileList) {
|
||||
$dh = $this->wrapSource($fileList);
|
||||
$this->basicTest($fileList, $dh);
|
||||
}
|
||||
}
|
|
@ -1,59 +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\Streams\Tests;
|
||||
|
||||
class NullWrapper extends Wrapper {
|
||||
|
||||
/**
|
||||
* @param resource $source
|
||||
* @return resource
|
||||
*/
|
||||
protected function wrapSource($source) {
|
||||
return \Icewind\Streams\NullWrapper::wrap($source);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \BadMethodCallException
|
||||
*/
|
||||
public function testNoContext() {
|
||||
stream_wrapper_register('null', '\Icewind\Streams\NullWrapper');
|
||||
$context = stream_context_create(array());
|
||||
try {
|
||||
fopen('null://', 'r+', false, $context);
|
||||
stream_wrapper_unregister('null');
|
||||
} catch (\Exception $e) {
|
||||
stream_wrapper_unregister('null');
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \BadMethodCallException
|
||||
*/
|
||||
public function testNoSource() {
|
||||
stream_wrapper_register('null', '\Icewind\Streams\NullWrapper');
|
||||
$context = stream_context_create(array(
|
||||
'null' => array(
|
||||
'source' => 'bar'
|
||||
)
|
||||
));
|
||||
try {
|
||||
fopen('null://', 'r+', false, $context);
|
||||
} catch (\Exception $e) {
|
||||
stream_wrapper_unregister('null');
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \BadMethodCallException
|
||||
*/
|
||||
public function testWrapInvalidSource() {
|
||||
$this->wrapSource('foo');
|
||||
}
|
||||
}
|
|
@ -1,105 +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\Streams\Tests;
|
||||
|
||||
abstract class Wrapper extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @param resource $source
|
||||
* @return resource
|
||||
*/
|
||||
abstract protected function wrapSource($source);
|
||||
|
||||
public function testRead() {
|
||||
$source = fopen('php://temp', 'r+');
|
||||
fwrite($source, 'foobar');
|
||||
rewind($source);
|
||||
|
||||
$wrapped = $this->wrapSource($source);
|
||||
$this->assertEquals('foo', fread($wrapped, 3));
|
||||
$this->assertEquals('bar', fread($wrapped, 3));
|
||||
$this->assertEquals('', fread($wrapped, 3));
|
||||
}
|
||||
|
||||
public function testWrite() {
|
||||
$source = fopen('php://temp', 'r+');
|
||||
rewind($source);
|
||||
|
||||
$wrapped = $this->wrapSource($source);
|
||||
|
||||
$this->assertEquals(6, fwrite($wrapped, 'foobar'));
|
||||
rewind($source);
|
||||
$this->assertEquals('foobar', stream_get_contents($source));
|
||||
}
|
||||
|
||||
public function testClose() {
|
||||
$source = fopen('php://temp', 'r+');
|
||||
rewind($source);
|
||||
|
||||
$wrapped = $this->wrapSource($source);
|
||||
|
||||
fclose($wrapped);
|
||||
$this->assertFalse(is_resource($source));
|
||||
}
|
||||
|
||||
public function testSeekTell() {
|
||||
$source = fopen('php://temp', 'r+');
|
||||
fwrite($source, 'foobar');
|
||||
rewind($source);
|
||||
|
||||
$wrapped = $this->wrapSource($source);
|
||||
|
||||
$this->assertEquals(0, ftell($wrapped));
|
||||
|
||||
fseek($wrapped, 2);
|
||||
$this->assertEquals(2, ftell($source));
|
||||
$this->assertEquals(2, ftell($wrapped));
|
||||
|
||||
fseek($wrapped, 2, SEEK_CUR);
|
||||
$this->assertEquals(4, ftell($source));
|
||||
$this->assertEquals(4, ftell($wrapped));
|
||||
|
||||
fseek($wrapped, -1, SEEK_END);
|
||||
$this->assertEquals(5, ftell($source));
|
||||
$this->assertEquals(5, ftell($wrapped));
|
||||
}
|
||||
|
||||
public function testStat() {
|
||||
$source = fopen(__FILE__, 'r+');
|
||||
$wrapped = $this->wrapSource($source);
|
||||
$this->assertEquals(stat(__FILE__), fstat($wrapped));
|
||||
}
|
||||
|
||||
public function testTruncate() {
|
||||
if (version_compare(phpversion(), '5.4.0', '<')) {
|
||||
$this->markTestSkipped('php <5.4 doesn\'t support truncate for stream wrappers');
|
||||
}
|
||||
$source = fopen('php://temp', 'r+');
|
||||
fwrite($source, 'foobar');
|
||||
rewind($source);
|
||||
$wrapped = $this->wrapSource($source);
|
||||
|
||||
ftruncate($wrapped, 2);
|
||||
$this->assertEquals('fo', fread($wrapped, 10));
|
||||
}
|
||||
|
||||
public function testLock() {
|
||||
$source = tmpfile();
|
||||
$wrapped = $this->wrapSource($source);
|
||||
if (!flock($wrapped, LOCK_EX)) {
|
||||
$this->fail('Unable to acquire lock');
|
||||
}
|
||||
}
|
||||
|
||||
public function testStreamOptions() {
|
||||
$source = fopen('php://temp', 'r+');
|
||||
$wrapped = $this->wrapSource($source);
|
||||
stream_set_blocking($wrapped, 0);
|
||||
stream_set_timeout($wrapped, 1, 0);
|
||||
stream_set_write_buffer($wrapped, 0);
|
||||
}
|
||||
}
|
|
@ -1,9 +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
|
||||
*/
|
||||
|
||||
date_default_timezone_set('UTC');
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<phpunit bootstrap="bootstrap.php">
|
||||
<testsuite name='Stream'>
|
||||
<directory suffix='.php'>./</directory>
|
||||
</testsuite>
|
||||
</phpunit>
|
Loading…
Reference in New Issue