$mode file mode integer e.g 0664
* @param bool $recursive whether to set recursively (directories)
* @return Loco_fs_File
*/
public function chmod( $mode, $recursive = false ){
$this->getWriteContext()->chmod( $mode, $recursive );
return $this->clearStat();
}
/**
* Clear stat cache if any file data has changed
* @return Loco_fs_File
*/
public function clearStat(){
$this->info = null;
// PHP 5.3.0 Added optional clear_realpath_cache and filename parameters.
if( version_compare( PHP_VERSION, '5.3.0', '>=' ) ){
clearstatcache( true, $this->path );
}
// else no choice but to drop entire stat cache
else {
clearstatcache();
}
return $this;
}
/**
* @return string
*/
public function __toString(){
return $this->getPath();
}
/**
* Check if passed path is equal to ours
* @param string|self $ref
* @return bool
*/
public function equal( $ref ){
return $this->path === (string) $ref;
}
/**
* Normalize path for string comparison, resolves redundant dots and slashes.
* @param string $base path to prefix
* @return string
*/
public function normalize( $base = '' ){
if( $path = self::abs($base) ){
$base = $path;
}
if( $base !== $this->base ){
$path = $this->path;
if( '' === $path ){
$this->setPath($base);
}
else {
if( ! $this->rel || ! $base ){
$b = [];
}
else {
$b = self::explode( $base, [] );
}
$b = self::explode( $path, $b );
$this->setPath( implode('/',$b) );
}
$this->base = $base;
}
return $this->path;
}
/**
* Get real path if file is real, but without altering internal path property.
* Also skips call to realpath() when likely to raise E_WARNING due to open_basedir
* @return string
*/
public function getRealPath(){
if( $this->readable() ){
$path = realpath( $this->getPath() );
if( is_string($path) ){
return $path;
}
}
return '';
}
/**
* @param string $path
* @param string[] $b
* @return array
*/
private static function explode( $path, array $b ){
$a = explode( '/', $path );
foreach( $a as $i => $s ){
if( '' === $s ){
if( 0 !== $i ){
continue;
}
}
if( '.' === $s ){
continue;
}
if( '..' === $s ){
if( array_pop($b) ){
continue;
}
}
$b[] = $s;
}
return $b;
}
/**
* Get path relative to given location, unless path is already relative
* @param string $base Base path
* @return string path relative to given base
*/
public function getRelativePath( $base ){
$path = $this->normalize();
if( self::abs($path) ){
// base may require normalizing
$file = new Loco_fs_File($base);
$base = $file->normalize();
$length = strlen($base)+1;
// if we are below given base path, return ./relative
if( substr($path,0,$length) === $base.'/' ){
if( strlen($path) > $length ){
return substr( $path, $length );
}
// else paths were identical
return '';
}
// else attempt to find nearest common root
$i = 0;
$source = explode('/',$base);
$target = explode('/',$path);
while( isset($source[$i]) && isset($target[$i]) && $source[$i] === $target[$i] ){
$i++;
}
if( $i > 1 ){
$depth = count($source) - $i;
$build = array_merge( array_fill( 0, $depth, '..' ), array_slice( $target, $i ) );
$path = implode( '/', $build );
}
}
// else return unmodified
return $path;
}
/**
* @return bool
*/
public function isDirectory(){
if( $this->readable() ){
return is_dir($this->path);
}
return '' === $this->extension();
}
/**
* Load contents of file into a string
* @return string
*/
public function getContents(){
return file_get_contents( $this->path );
}
/**
* Check if path is under a theme directory
* @return bool
*/
public function underThemeDirectory(){
return Loco_fs_Locations::getThemes()->check( $this->path );
}
/**
* Check if path is under a plugin directory
* @return bool
*/
public function underPluginDirectory(){
return Loco_fs_Locations::getPlugins()->check( $this->path );
}
/**
* Check if path is under wp-content directory
* @return bool
*/
public function underContentDirectory(){
return Loco_fs_Locations::getContent()->check( $this->path );
}
/**
* Check if path is under WordPress root directory (ABSPATH)
* @return bool
*/
public function underWordPressDirectory(){
return Loco_fs_Locations::getRoot()->check( $this->path );
}
/**
* Check if path is under the global system directory
* @return bool
*/
public function underGlobalDirectory(){
return Loco_fs_Locations::getGlobal()->check( $this->path );
}
/**
* @return Loco_fs_Directory|null
*/
public function getParent(){
$dir = null;
$path = $this->dirname();
if( '.' !== $path && $this->path !== $path ){
$dir = new Loco_fs_Directory( $path );
$dir->cloneWriteContext( $this->w );
}
return $dir;
}
/**
* Copy this file for real
* @param string $dest new path
* @throws Loco_error_WriteException
* @return Loco_fs_File new file
*/
public function copy( $dest ){
$copy = clone $this;
$copy->path = $dest;
$copy->clearStat();
$this->getWriteContext()->copy($copy);
return $copy;
}
/**
* Move/rename this file for real
* @param Loco_fs_File $dest target file with new path
* @throws Loco_error_WriteException
* @return Loco_fs_File original file that should no longer exist
*/
public function move( Loco_fs_File $dest ){
$this->getWriteContext()->move($dest);
return $this->clearStat();
}
/**
* Delete this file for real
* @throws Loco_error_WriteException
* @return Loco_fs_File
*/
public function unlink(){
$recursive = $this->isDirectory();
$this->getWriteContext()->delete( $recursive );
return $this->clearStat();
}
/**
* Copy this object with an alternative file extension
* @param string $ext new extension
* @return self
*/
public function cloneExtension( $ext ){
return $this->cloneBasename( $this->filename().'.'.ltrim($ext,'.') );
}
/**
* Copy this object with an alternative name under the same directory
* @param string $name new name
* @return self
*/
public function cloneBasename( $name ){
$file = clone $this;
$file->path = rtrim($file->dirname(),'/').'/'.$name;
$file->info = null;
return $file;
}
/**
* Ensure full parent directory tree exists
* @return Loco_fs_Directory|null
*/
public function createParent(){
$dir = $this->getParent();
if( $dir instanceof Loco_fs_Directory && ! $dir->exists() ){
$dir->mkdir();
}
return $dir;
}
/**
* @param string $data file contents
* @return int number of bytes written to file
*/
public function putContents( $data ){
$this->getWriteContext()->putContents($data);
$this->clearStat();
return $this->size();
}
/**
* Establish what part of the WordPress file system this is.
* Value is that used by WP_Automatic_Updater::should_update.
* @return string "core", "plugin", "theme" or "translation"
*/
public function getUpdateType(){
// global languages directory root, and canonical subdirectories
$dirpath = (string) ( $this->isDirectory() ? $this : $this->getParent() );
$sub = Loco_fs_Locations::getGlobal()->rel($dirpath);
if( is_string($sub) && '' !== $sub ){
list($root) = explode('/', $sub, 2 );
if( '.' === $root || 'themes' === $root || 'plugins' === $root ){
return 'translation';
}
}
// theme and plugin locations can be at any depth
else if( $this->underThemeDirectory() ){
return 'theme';
}
else if( $this->underPluginDirectory() ){
return 'plugin';
}
// core locations are under WordPress root, but not under wp-content
else if( $this->underWordPressDirectory() && ! $this->underContentDirectory() ){
return 'core';
}
// else not an update type
return '';
}
/**
* Get MD5 hash of file contents
* @return string
*/
public function md5(){
if( $this->exists() ) {
return md5_file( $this->path );
}
else {
return 'd41d8cd98f00b204e9800998ecf8427e';
}
}
}