CallbackWrapper.php 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2014 Robin Appelman <robin@icewind.nl>
  4. * SPDX-License-Identifier: MIT
  5. */
  6. namespace Icewind\Streams;
  7. /**
  8. * Wrapper that provides callbacks for write, read and close
  9. *
  10. * The following options should be passed in the context when opening the stream
  11. * [
  12. * 'callback' => [
  13. * 'source' => resource
  14. * 'read' => function($count){} (optional)
  15. * 'write' => function($data){} (optional)
  16. * 'close' => function(){} (optional)
  17. * 'readdir' => function(){} (optional)
  18. * ]
  19. * ]
  20. *
  21. * All callbacks are called after the operation is executed on the source stream
  22. */
  23. class CallbackWrapper extends Wrapper {
  24. /**
  25. * @var callable|null
  26. */
  27. protected $readCallback;
  28. /**
  29. * @var callable|null
  30. */
  31. protected $writeCallback;
  32. /**
  33. * @var callable|null
  34. */
  35. protected $closeCallback;
  36. /**
  37. * @var callable|null
  38. */
  39. protected $readDirCallBack;
  40. /**
  41. * @var callable|null
  42. */
  43. protected $preCloseCallback;
  44. /**
  45. * Wraps a stream with the provided callbacks
  46. *
  47. * @param resource $source
  48. * @param callable|null $read (optional)
  49. * @param callable|null $write (optional)
  50. * @param callable|null $close (optional)
  51. * @param callable|null $readDir (optional)
  52. * @param callable|null $preClose (optional)
  53. * @return resource|false
  54. *
  55. */
  56. public static function wrap($source, $read = null, $write = null, $close = null, $readDir = null, $preClose = null) {
  57. $context = [
  58. 'source' => $source,
  59. 'read' => $read,
  60. 'write' => $write,
  61. 'close' => $close,
  62. 'readDir' => $readDir,
  63. 'preClose' => $preClose,
  64. ];
  65. return self::wrapSource($source, $context);
  66. }
  67. protected function open() {
  68. $context = $this->loadContext();
  69. $this->readCallback = $context['read'];
  70. $this->writeCallback = $context['write'];
  71. $this->closeCallback = $context['close'];
  72. $this->readDirCallBack = $context['readDir'];
  73. $this->preCloseCallback = $context['preClose'];
  74. return true;
  75. }
  76. public function dir_opendir($path, $options) {
  77. return $this->open();
  78. }
  79. public function stream_open($path, $mode, $options, &$opened_path) {
  80. return $this->open();
  81. }
  82. public function stream_read($count) {
  83. $result = parent::stream_read($count);
  84. if (is_callable($this->readCallback)) {
  85. call_user_func($this->readCallback, strlen($result));
  86. }
  87. return $result;
  88. }
  89. public function stream_write($data) {
  90. $result = parent::stream_write($data);
  91. if (is_callable($this->writeCallback)) {
  92. call_user_func($this->writeCallback, $data);
  93. }
  94. return $result;
  95. }
  96. public function stream_close() {
  97. if (is_callable($this->preCloseCallback)) {
  98. call_user_func($this->preCloseCallback, $this->source);
  99. // prevent further calls by potential PHP 7 GC ghosts
  100. $this->preCloseCallback = null;
  101. }
  102. $result = parent::stream_close();
  103. if (is_callable($this->closeCallback)) {
  104. call_user_func($this->closeCallback);
  105. // prevent further calls by potential PHP 7 GC ghosts
  106. $this->closeCallback = null;
  107. }
  108. return $result;
  109. }
  110. public function dir_readdir() {
  111. $result = parent::dir_readdir();
  112. if (is_callable($this->readDirCallBack)) {
  113. call_user_func($this->readDirCallBack);
  114. }
  115. return $result;
  116. }
  117. }