1<?php 2 3/** 4 * Hoa 5 * 6 * 7 * @license 8 * 9 * New BSD License 10 * 11 * Copyright © 2007-2017, Hoa community. All rights reserved. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions are met: 15 * * Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * * Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * * Neither the name of the Hoa nor the names of its contributors may be 21 * used to endorse or promote products derived from this software without 22 * specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE 28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 * POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37namespace Hoa\File; 38 39use Hoa\Consistency; 40use Hoa\Stream; 41 42/** 43 * Class \Hoa\File. 44 * 45 * File handler. 46 * 47 * @copyright Copyright © 2007-2017 Hoa community 48 * @license New BSD License 49 */ 50abstract class File 51 extends Generic 52 implements Stream\IStream\Bufferable, 53 Stream\IStream\Lockable, 54 Stream\IStream\Pointable 55{ 56 /** 57 * Open for reading only; place the file pointer at the beginning of the 58 * file. 59 * 60 * @const string 61 */ 62 const MODE_READ = 'rb'; 63 64 /** 65 * Open for reading and writing; place the file pointer at the beginning of 66 * the file. 67 * 68 * @const string 69 */ 70 const MODE_READ_WRITE = 'r+b'; 71 72 /** 73 * Open for writing only; place the file pointer at the beginning of the 74 * file and truncate the file to zero length. If the file does not exist, 75 * attempt to create it. 76 * 77 * @const string 78 */ 79 const MODE_TRUNCATE_WRITE = 'wb'; 80 81 /** 82 * Open for reading and writing; place the file pointer at the beginning of 83 * the file and truncate the file to zero length. If the file does not 84 * exist, attempt to create it. 85 * 86 * @const string 87 */ 88 const MODE_TRUNCATE_READ_WRITE = 'w+b'; 89 90 /** 91 * Open for writing only; place the file pointer at the end of the file. If 92 * the file does not exist, attempt to create it. 93 * 94 * @const string 95 */ 96 const MODE_APPEND_WRITE = 'ab'; 97 98 /** 99 * Open for reading and writing; place the file pointer at the end of the 100 * file. If the file does not exist, attempt to create it. 101 * 102 * @const string 103 */ 104 const MODE_APPEND_READ_WRITE = 'a+b'; 105 106 /** 107 * Create and open for writing only; place the file pointer at the beginning 108 * of the file. If the file already exits, the fopen() call with fail by 109 * returning false and generating an error of level E_WARNING. If the file 110 * does not exist, attempt to create it. This is equivalent to specifying 111 * O_EXCL | O_CREAT flags for the underlying open(2) system call. 112 * 113 * @const string 114 */ 115 const MODE_CREATE_WRITE = 'xb'; 116 117 /** 118 * Create and open for reading and writing; place the file pointer at the 119 * beginning of the file. If the file already exists, the fopen() call with 120 * fail by returning false and generating an error of level E_WARNING. If 121 * the file does not exist, attempt to create it. This is equivalent to 122 * specifying O_EXCL | O_CREAT flags for the underlying open(2) system call. 123 * 124 * @const string 125 */ 126 const MODE_CREATE_READ_WRITE = 'x+b'; 127 128 129 130 /** 131 * Open a file. 132 * 133 * @param string $streamName Stream name (or file descriptor). 134 * @param string $mode Open mode, see the self::MODE_* 135 * constants. 136 * @param string $context Context ID (please, see the 137 * \Hoa\Stream\Context class). 138 * @param bool $wait Differ opening or not. 139 * @throws \Hoa\File\Exception 140 */ 141 public function __construct( 142 $streamName, 143 $mode, 144 $context = null, 145 $wait = false 146 ) { 147 $this->setMode($mode); 148 149 switch ($streamName) { 150 151 case '0': 152 $streamName = 'php://stdin'; 153 154 break; 155 156 case '1': 157 $streamName = 'php://stdout'; 158 159 break; 160 161 case '2': 162 $streamName = 'php://stderr'; 163 164 break; 165 166 default: 167 if (true === ctype_digit($streamName)) { 168 if (PHP_VERSION_ID >= 50306) { 169 $streamName = 'php://fd/' . $streamName; 170 } else { 171 throw new Exception( 172 'You need PHP5.3.6 to use a file descriptor ' . 173 'other than 0, 1 or 2 (tried %d with PHP%s).', 174 0, 175 [$streamName, PHP_VERSION] 176 ); 177 } 178 } 179 } 180 181 parent::__construct($streamName, $context, $wait); 182 183 return; 184 } 185 186 /** 187 * Open the stream and return the associated resource. 188 * 189 * @param string $streamName Stream name (e.g. path or URL). 190 * @param \Hoa\Stream\Context $context Context. 191 * @return resource 192 * @throws \Hoa\File\Exception\FileDoesNotExist 193 * @throws \Hoa\File\Exception 194 */ 195 protected function &_open($streamName, Stream\Context $context = null) 196 { 197 if (substr($streamName, 0, 4) == 'file' && 198 false === is_dir(dirname($streamName))) { 199 throw new Exception( 200 'Directory %s does not exist. Could not open file %s.', 201 1, 202 [dirname($streamName), basename($streamName)] 203 ); 204 } 205 206 if (null === $context) { 207 if (false === $out = @fopen($streamName, $this->getMode(), true)) { 208 throw new Exception( 209 'Failed to open stream %s.', 210 2, 211 $streamName 212 ); 213 } 214 215 return $out; 216 } 217 218 $out = @fopen( 219 $streamName, 220 $this->getMode(), 221 true, 222 $context->getContext() 223 ); 224 225 if (false === $out) { 226 throw new Exception( 227 'Failed to open stream %s.', 228 3, 229 $streamName 230 ); 231 } 232 233 return $out; 234 } 235 236 /** 237 * Close the current stream. 238 * 239 * @return bool 240 */ 241 protected function _close() 242 { 243 return @fclose($this->getStream()); 244 } 245 246 /** 247 * Start a new buffer. 248 * The callable acts like a light filter. 249 * 250 * @param mixed $callable Callable. 251 * @param int $size Size. 252 * @return int 253 */ 254 public function newBuffer($callable = null, $size = null) 255 { 256 $this->setStreamBuffer($size); 257 258 //@TODO manage $callable as a filter? 259 260 return 1; 261 } 262 263 /** 264 * Flush the output to a stream. 265 * 266 * @return bool 267 */ 268 public function flush() 269 { 270 return fflush($this->getStream()); 271 } 272 273 /** 274 * Delete buffer. 275 * 276 * @return bool 277 */ 278 public function deleteBuffer() 279 { 280 return $this->disableStreamBuffer(); 281 } 282 283 /** 284 * Get bufffer level. 285 * 286 * @return int 287 */ 288 public function getBufferLevel() 289 { 290 return 1; 291 } 292 293 /** 294 * Get buffer size. 295 * 296 * @return int 297 */ 298 public function getBufferSize() 299 { 300 return $this->getStreamBufferSize(); 301 } 302 303 /** 304 * Portable advisory locking. 305 * 306 * @param int $operation Operation, use the 307 * \Hoa\Stream\IStream\Lockable::LOCK_* constants. 308 * @return bool 309 */ 310 public function lock($operation) 311 { 312 return flock($this->getStream(), $operation); 313 } 314 315 /** 316 * Rewind the position of a stream pointer. 317 * 318 * @return bool 319 */ 320 public function rewind() 321 { 322 return rewind($this->getStream()); 323 } 324 325 /** 326 * Seek on a stream pointer. 327 * 328 * @param int $offset Offset (negative value should be supported). 329 * @param int $whence Whence, use the 330 * \Hoa\Stream\IStream\Pointable::SEEK_* constants. 331 * @return int 332 */ 333 public function seek($offset, $whence = Stream\IStream\Pointable::SEEK_SET) 334 { 335 return fseek($this->getStream(), $offset, $whence); 336 } 337 338 /** 339 * Get the current position of the stream pointer. 340 * 341 * @return int 342 */ 343 public function tell() 344 { 345 $stream = $this->getStream(); 346 347 if (null === $stream) { 348 return 0; 349 } 350 351 return ftell($stream); 352 } 353 354 /** 355 * Create a file. 356 * 357 * @param string $name File name. 358 * @param mixed $dummy To be compatible with childs. 359 * @return bool 360 */ 361 public static function create($name, $dummy) 362 { 363 if (file_exists($name)) { 364 return true; 365 } 366 367 return touch($name); 368 } 369} 370 371/** 372 * Flex entity. 373 */ 374Consistency::flexEntity('Hoa\File\File'); 375