1<?php 2/** 3 * @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl> 4 * 5 * @license GNU AGPL version 3 or any later version 6 * 7 * This program is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU Affero General Public License as 9 * published by the Free Software Foundation, either version 3 of the 10 * License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU Affero General Public License for more details. 16 * 17 * You should have received a copy of the GNU Affero General Public License 18 * along with this program. If not, see <http://www.gnu.org/licenses/>. 19 * 20 */ 21 22namespace Icewind\Streams; 23 24/** 25 * Wrapper that counts the amount of data read and written 26 * 27 * The following options should be passed in the context when opening the stream 28 * [ 29 * 'callback' => [ 30 * 'source' => resource 31 * 'callback' => function($readCount, $writeCount){} 32 * ] 33 * ] 34 * 35 * The callback will be called when the stream is closed 36 */ 37class CountWrapper extends Wrapper { 38 /** 39 * @var int 40 */ 41 protected $readCount = 0; 42 43 /** 44 * @var int 45 */ 46 protected $writeCount = 0; 47 48 /** 49 * @var callable 50 */ 51 protected $callback; 52 53 /** 54 * Wraps a stream with the provided callbacks 55 * 56 * @param resource $source 57 * @param callable $callback 58 * @return resource|bool 59 * 60 * @throws \BadMethodCallException 61 */ 62 public static function wrap($source, $callback) { 63 if (!is_callable($callback)) { 64 throw new \InvalidArgumentException('Invalid or missing callback'); 65 } 66 return self::wrapSource($source, [ 67 'source' => $source, 68 'callback' => $callback 69 ]); 70 } 71 72 protected function open() { 73 $context = $this->loadContext(); 74 $this->callback = $context['callback']; 75 return true; 76 } 77 78 public function dir_opendir($path, $options) { 79 return $this->open(); 80 } 81 82 public function stream_open($path, $mode, $options, &$opened_path) { 83 return $this->open(); 84 } 85 86 public function stream_read($count) { 87 $result = parent::stream_read($count); 88 $this->readCount += strlen($result); 89 return $result; 90 } 91 92 public function stream_write($data) { 93 $result = parent::stream_write($data); 94 $this->writeCount += strlen($data); 95 return $result; 96 } 97 98 public function stream_close() { 99 $result = parent::stream_close(); 100 call_user_func($this->callback, $this->readCount, $this->writeCount); 101 return $result; 102 } 103} 104