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\Stream; 40 41/** 42 * Class \Hoa\File\Generic. 43 * 44 * Describe a super-file. 45 * 46 * @copyright Copyright © 2007-2017 Hoa community 47 * @license New BSD License 48 */ 49abstract class Generic 50 extends Stream 51 implements Stream\IStream\Pathable, 52 Stream\IStream\Statable, 53 Stream\IStream\Touchable 54{ 55 /** 56 * Mode. 57 * 58 * @var string 59 */ 60 protected $_mode = null; 61 62 63 64 /** 65 * Get filename component of path. 66 * 67 * @return string 68 */ 69 public function getBasename() 70 { 71 return basename($this->getStreamName()); 72 } 73 74 /** 75 * Get directory name component of path. 76 * 77 * @return string 78 */ 79 public function getDirname() 80 { 81 return dirname($this->getStreamName()); 82 } 83 84 /** 85 * Get size. 86 * 87 * @return int 88 */ 89 public function getSize() 90 { 91 if (false === $this->getStatistic()) { 92 return false; 93 } 94 95 return filesize($this->getStreamName()); 96 } 97 98 /** 99 * Get informations about a file. 100 * 101 * @return array 102 */ 103 public function getStatistic() 104 { 105 return fstat($this->getStream()); 106 } 107 108 /** 109 * Get last access time of file. 110 * 111 * @return int 112 */ 113 public function getATime() 114 { 115 return fileatime($this->getStreamName()); 116 } 117 118 /** 119 * Get inode change time of file. 120 * 121 * @return int 122 */ 123 public function getCTime() 124 { 125 return filectime($this->getStreamName()); 126 } 127 128 /** 129 * Get file modification time. 130 * 131 * @return int 132 */ 133 public function getMTime() 134 { 135 return filemtime($this->getStreamName()); 136 } 137 138 /** 139 * Get file group. 140 * 141 * @return int 142 */ 143 public function getGroup() 144 { 145 return filegroup($this->getStreamName()); 146 } 147 148 /** 149 * Get file owner. 150 * 151 * @return int 152 */ 153 public function getOwner() 154 { 155 return fileowner($this->getStreamName()); 156 } 157 158 /** 159 * Get file permissions. 160 * 161 * @return int 162 */ 163 public function getPermissions() 164 { 165 return fileperms($this->getStreamName()); 166 } 167 168 /** 169 * Get file permissions as a string. 170 * Result sould be interpreted like this: 171 * * s: socket; 172 * * l: symbolic link; 173 * * -: regular; 174 * * b: block special; 175 * * d: directory; 176 * * c: character special; 177 * * p: FIFO pipe; 178 * * u: unknown. 179 * 180 * @return string 181 */ 182 public function getReadablePermissions() 183 { 184 $p = $this->getPermissions(); 185 186 if (($p & 0xC000) == 0xC000) { 187 $out = 's'; 188 } elseif (($p & 0xA000) == 0xA000) { 189 $out = 'l'; 190 } elseif (($p & 0x8000) == 0x8000) { 191 $out = '-'; 192 } elseif (($p & 0x6000) == 0x6000) { 193 $out = 'b'; 194 } elseif (($p & 0x4000) == 0x4000) { 195 $out = 'd'; 196 } elseif (($p & 0x2000) == 0x2000) { 197 $out = 'c'; 198 } elseif (($p & 0x1000) == 0x1000) { 199 $out = 'p'; 200 } else { 201 $out = 'u'; 202 } 203 204 $out .= 205 (($p & 0x0100) ? 'r' : '-') . 206 (($p & 0x0080) ? 'w' : '-') . 207 (($p & 0x0040) ? 208 (($p & 0x0800) ? 's' : 'x') : 209 (($p & 0x0800) ? 'S' : '-')) . 210 (($p & 0x0020) ? 'r' : '-') . 211 (($p & 0x0010) ? 'w' : '-') . 212 (($p & 0x0008) ? 213 (($p & 0x0400) ? 's' : 'x') : 214 (($p & 0x0400) ? 'S' : '-')) . 215 (($p & 0x0004) ? 'r' : '-') . 216 (($p & 0x0002) ? 'w' : '-') . 217 (($p & 0x0001) ? 218 (($p & 0x0200) ? 't' : 'x') : 219 (($p & 0x0200) ? 'T' : '-')); 220 221 return $out; 222 } 223 224 /** 225 * Check if the file is readable. 226 * 227 * @return bool 228 */ 229 public function isReadable() 230 { 231 return is_readable($this->getStreamName()); 232 } 233 234 /** 235 * Check if the file is writable. 236 * 237 * @return bool 238 */ 239 public function isWritable() 240 { 241 return is_writable($this->getStreamName()); 242 } 243 244 /** 245 * Check if the file is executable. 246 * 247 * @return bool 248 */ 249 public function isExecutable() 250 { 251 return is_executable($this->getStreamName()); 252 } 253 254 /** 255 * Clear file status cache. 256 * 257 * @return void 258 */ 259 public function clearStatisticCache() 260 { 261 clearstatcache(true, $this->getStreamName()); 262 263 return; 264 } 265 266 /** 267 * Clear all files status cache. 268 * 269 * @return void 270 */ 271 public static function clearAllStatisticCaches() 272 { 273 clearstatcache(); 274 275 return; 276 } 277 278 /** 279 * Set access and modification time of file. 280 * 281 * @param int $time Time. If equals to -1, time() should be used. 282 * @param int $atime Access time. If equals to -1, $time should be 283 * used. 284 * @return bool 285 */ 286 public function touch($time = -1, $atime = -1) 287 { 288 if ($time == -1) { 289 $time = time(); 290 } 291 292 if ($atime == -1) { 293 $atime = $time; 294 } 295 296 return touch($this->getStreamName(), $time, $atime); 297 } 298 299 /** 300 * Copy file. 301 * Return the destination file path if succeed, false otherwise. 302 * 303 * @param string $to Destination path. 304 * @param bool $force Force to copy if the file $to already exists. 305 * Use the \Hoa\Stream\IStream\Touchable::*OVERWRITE 306 * constants. 307 * @return bool 308 */ 309 public function copy($to, $force = Stream\IStream\Touchable::DO_NOT_OVERWRITE) 310 { 311 $from = $this->getStreamName(); 312 313 if ($force === Stream\IStream\Touchable::DO_NOT_OVERWRITE && 314 true === file_exists($to)) { 315 return true; 316 } 317 318 if (null === $this->getStreamContext()) { 319 return @copy($from, $to); 320 } 321 322 return @copy($from, $to, $this->getStreamContext()->getContext()); 323 } 324 325 /** 326 * Move a file. 327 * 328 * @param string $name New name. 329 * @param bool $force Force to move if the file $name already 330 * exists. 331 * Use the \Hoa\Stream\IStream\Touchable::*OVERWRITE 332 * constants. 333 * @param bool $mkdir Force to make directory if does not exist. 334 * Use the \Hoa\Stream\IStream\Touchable::*DIRECTORY 335 * constants. 336 * @return bool 337 */ 338 public function move( 339 $name, 340 $force = Stream\IStream\Touchable::DO_NOT_OVERWRITE, 341 $mkdir = Stream\IStream\Touchable::DO_NOT_MAKE_DIRECTORY 342 ) { 343 $from = $this->getStreamName(); 344 345 if ($force === Stream\IStream\Touchable::DO_NOT_OVERWRITE && 346 true === file_exists($name)) { 347 return false; 348 } 349 350 if (Stream\IStream\Touchable::MAKE_DIRECTORY === $mkdir) { 351 Directory::create( 352 dirname($name), 353 Directory::MODE_CREATE_RECURSIVE 354 ); 355 } 356 357 if (null === $this->getStreamContext()) { 358 return @rename($from, $name); 359 } 360 361 return @rename($from, $name, $this->getStreamContext()->getContext()); 362 } 363 364 /** 365 * Delete a file. 366 * 367 * @return bool 368 */ 369 public function delete() 370 { 371 if (null === $this->getStreamContext()) { 372 return @unlink($this->getStreamName()); 373 } 374 375 return @unlink( 376 $this->getStreamName(), 377 $this->getStreamContext()->getContext() 378 ); 379 } 380 381 /** 382 * Change file group. 383 * 384 * @param mixed $group Group name or number. 385 * @return bool 386 */ 387 public function changeGroup($group) 388 { 389 return chgrp($this->getStreamName(), $group); 390 } 391 392 /** 393 * Change file mode. 394 * 395 * @param int $mode Mode (in octal!). 396 * @return bool 397 */ 398 public function changeMode($mode) 399 { 400 return chmod($this->getStreamName(), $mode); 401 } 402 403 /** 404 * Change file owner. 405 * 406 * @param mixed $user User. 407 * @return bool 408 */ 409 public function changeOwner($user) 410 { 411 return chown($this->getStreamName(), $user); 412 } 413 414 /** 415 * Change the current umask. 416 * 417 * @param int $umask Umask (in octal!). If null, given the current 418 * umask value. 419 * @return int 420 */ 421 public static function umask($umask = null) 422 { 423 if (null === $umask) { 424 return umask(); 425 } 426 427 return umask($umask); 428 } 429 430 /** 431 * Check if it is a file. 432 * 433 * @return bool 434 */ 435 public function isFile() 436 { 437 return is_file($this->getStreamName()); 438 } 439 440 /** 441 * Check if it is a link. 442 * 443 * @return bool 444 */ 445 public function isLink() 446 { 447 return is_link($this->getStreamName()); 448 } 449 450 /** 451 * Check if it is a directory. 452 * 453 * @return bool 454 */ 455 public function isDirectory() 456 { 457 return is_dir($this->getStreamName()); 458 } 459 460 /** 461 * Check if it is a socket. 462 * 463 * @return bool 464 */ 465 public function isSocket() 466 { 467 return filetype($this->getStreamName()) == 'socket'; 468 } 469 470 /** 471 * Check if it is a FIFO pipe. 472 * 473 * @return bool 474 */ 475 public function isFIFOPipe() 476 { 477 return filetype($this->getStreamName()) == 'fifo'; 478 } 479 480 /** 481 * Check if it is character special file. 482 * 483 * @return bool 484 */ 485 public function isCharacterSpecial() 486 { 487 return filetype($this->getStreamName()) == 'char'; 488 } 489 490 /** 491 * Check if it is block special. 492 * 493 * @return bool 494 */ 495 public function isBlockSpecial() 496 { 497 return filetype($this->getStreamName()) == 'block'; 498 } 499 500 /** 501 * Check if it is an unknown type. 502 * 503 * @return bool 504 */ 505 public function isUnknown() 506 { 507 return filetype($this->getStreamName()) == 'unknown'; 508 } 509 510 /** 511 * Set the open mode. 512 * 513 * @param string $mode Open mode. Please, see the child::MODE_* 514 * constants. 515 * @return string 516 */ 517 protected function setMode($mode) 518 { 519 $old = $this->_mode; 520 $this->_mode = $mode; 521 522 return $old; 523 } 524 525 /** 526 * Get the open mode. 527 * 528 * @return string 529 */ 530 public function getMode() 531 { 532 return $this->_mode; 533 } 534 535 /** 536 * Get inode. 537 * 538 * @return int 539 */ 540 public function getINode() 541 { 542 return fileinode($this->getStreamName()); 543 } 544 545 /** 546 * Check if the system is case sensitive or not. 547 * 548 * @return bool 549 */ 550 public static function isCaseSensitive() 551 { 552 return !( 553 file_exists(mb_strtolower(__FILE__)) && 554 file_exists(mb_strtoupper(__FILE__)) 555 ); 556 } 557 558 /** 559 * Get a canonicalized absolute pathname. 560 * 561 * @return string 562 */ 563 public function getRealPath() 564 { 565 if (false === $out = realpath($this->getStreamName())) { 566 return $this->getStreamName(); 567 } 568 569 return $out; 570 } 571 572 /** 573 * Get file extension (if exists). 574 * 575 * @return string 576 */ 577 public function getExtension() 578 { 579 return pathinfo( 580 $this->getStreamName(), 581 PATHINFO_EXTENSION 582 ); 583 } 584 585 /** 586 * Get filename without extension. 587 * 588 * @return string 589 */ 590 public function getFilename() 591 { 592 $file = basename($this->getStreamName()); 593 594 if (defined('PATHINFO_FILENAME')) { 595 return pathinfo($file, PATHINFO_FILENAME); 596 } 597 598 if (strstr($file, '.')) { 599 return substr($file, 0, strrpos($file, '.')); 600 } 601 602 return $file; 603 } 604} 605