1<?php 2namespace GuzzleHttp\Stream; 3 4use GuzzleHttp\Stream\Exception\SeekException; 5 6/** 7 * Static utility class because PHP's autoloaders don't support the concept 8 * of namespaced function autoloading. 9 */ 10class Utils 11{ 12 /** 13 * Safely opens a PHP stream resource using a filename. 14 * 15 * When fopen fails, PHP normally raises a warning. This function adds an 16 * error handler that checks for errors and throws an exception instead. 17 * 18 * @param string $filename File to open 19 * @param string $mode Mode used to open the file 20 * 21 * @return resource 22 * @throws \RuntimeException if the file cannot be opened 23 */ 24 public static function open($filename, $mode) 25 { 26 $ex = null; 27 set_error_handler(function () use ($filename, $mode, &$ex) { 28 $ex = new \RuntimeException(sprintf( 29 'Unable to open %s using mode %s: %s', 30 $filename, 31 $mode, 32 func_get_args()[1] 33 )); 34 }); 35 36 $handle = fopen($filename, $mode); 37 restore_error_handler(); 38 39 if ($ex) { 40 /** @var $ex \RuntimeException */ 41 throw $ex; 42 } 43 44 return $handle; 45 } 46 47 /** 48 * Copy the contents of a stream into a string until the given number of 49 * bytes have been read. 50 * 51 * @param StreamInterface $stream Stream to read 52 * @param int $maxLen Maximum number of bytes to read. Pass -1 53 * to read the entire stream. 54 * @return string 55 */ 56 public static function copyToString(StreamInterface $stream, $maxLen = -1) 57 { 58 $buffer = ''; 59 60 if ($maxLen === -1) { 61 while (!$stream->eof()) { 62 $buf = $stream->read(1048576); 63 if ($buf === false) { 64 break; 65 } 66 $buffer .= $buf; 67 } 68 return $buffer; 69 } 70 71 $len = 0; 72 while (!$stream->eof() && $len < $maxLen) { 73 $buf = $stream->read($maxLen - $len); 74 if ($buf === false) { 75 break; 76 } 77 $buffer .= $buf; 78 $len = strlen($buffer); 79 } 80 81 return $buffer; 82 } 83 84 /** 85 * Copy the contents of a stream into another stream until the given number 86 * of bytes have been read. 87 * 88 * @param StreamInterface $source Stream to read from 89 * @param StreamInterface $dest Stream to write to 90 * @param int $maxLen Maximum number of bytes to read. Pass -1 91 * to read the entire stream. 92 */ 93 public static function copyToStream( 94 StreamInterface $source, 95 StreamInterface $dest, 96 $maxLen = -1 97 ) { 98 if ($maxLen === -1) { 99 while (!$source->eof()) { 100 if (!$dest->write($source->read(1048576))) { 101 break; 102 } 103 } 104 return; 105 } 106 107 $bytes = 0; 108 while (!$source->eof()) { 109 $buf = $source->read($maxLen - $bytes); 110 if (!($len = strlen($buf))) { 111 break; 112 } 113 $bytes += $len; 114 $dest->write($buf); 115 if ($bytes == $maxLen) { 116 break; 117 } 118 } 119 } 120 121 /** 122 * Calculate a hash of a Stream 123 * 124 * @param StreamInterface $stream Stream to calculate the hash for 125 * @param string $algo Hash algorithm (e.g. md5, crc32, etc) 126 * @param bool $rawOutput Whether or not to use raw output 127 * 128 * @return string Returns the hash of the stream 129 * @throws SeekException 130 */ 131 public static function hash( 132 StreamInterface $stream, 133 $algo, 134 $rawOutput = false 135 ) { 136 $pos = $stream->tell(); 137 138 if ($pos > 0 && !$stream->seek(0)) { 139 throw new SeekException($stream); 140 } 141 142 $ctx = hash_init($algo); 143 while (!$stream->eof()) { 144 hash_update($ctx, $stream->read(1048576)); 145 } 146 147 $out = hash_final($ctx, (bool) $rawOutput); 148 $stream->seek($pos); 149 150 return $out; 151 } 152 153 /** 154 * Read a line from the stream up to the maximum allowed buffer length 155 * 156 * @param StreamInterface $stream Stream to read from 157 * @param int $maxLength Maximum buffer length 158 * @param string $eol Line ending 159 * 160 * @return string|bool 161 */ 162 public static function readline(StreamInterface $stream, $maxLength = null, $eol = PHP_EOL) 163 { 164 $buffer = ''; 165 $size = 0; 166 $negEolLen = -strlen($eol); 167 168 while (!$stream->eof()) { 169 if (false === ($byte = $stream->read(1))) { 170 return $buffer; 171 } 172 $buffer .= $byte; 173 // Break when a new line is found or the max length - 1 is reached 174 if (++$size == $maxLength || substr($buffer, $negEolLen) === $eol) { 175 break; 176 } 177 } 178 179 return $buffer; 180 } 181 182 /** 183 * Alias of GuzzleHttp\Stream\Stream::factory. 184 * 185 * @param mixed $resource Resource to create 186 * @param array $options Associative array of stream options defined in 187 * {@see \GuzzleHttp\Stream\Stream::__construct} 188 * 189 * @return StreamInterface 190 * 191 * @see GuzzleHttp\Stream\Stream::factory 192 * @see GuzzleHttp\Stream\Stream::__construct 193 */ 194 public static function create($resource, array $options = []) 195 { 196 return Stream::factory($resource, $options); 197 } 198} 199