| 1 |
<?php |
| 2 |
|
| 3 |
namespace WPIDE\App\Services\Storage; |
| 4 |
|
| 5 |
use WPIDE\App\Classes\Freemius; |
| 6 |
use const WPIDE\Constants\DIR; |
| 7 |
use const WPIDE\Constants\CONTENT_DIR; |
| 8 |
use const WPIDE\Constants\FATAL_ERROR_DROPIN; |
| 9 |
use const WPIDE\Constants\IMAGE_DATA_DIR; |
| 10 |
use const WPIDE\Constants\TMP_DIR; |
| 11 |
use const WPIDE\Constants\WP_PATH; |
| 12 |
use WPIDE\App\AppConfig; |
| 13 |
use WPIDE\App\Services\Storage\Adapters\WPFileSystem; |
| 14 |
use WPIDE\App\Services\Storage\Adapters\DefaultFileSystem; |
| 15 |
class LocalFileSystem { |
| 16 |
public static function load( $root = null ) : Filesystem { |
| 17 |
$fs = new Filesystem(); |
| 18 |
$fs->init( self::getConfig( $root ) ); |
| 19 |
return $fs; |
| 20 |
} |
| 21 |
|
| 22 |
public static function getConfig( $root = null ) : array { |
| 23 |
if ( empty( $root ) ) { |
| 24 |
$root = self::getRootDir(); |
| 25 |
} |
| 26 |
if ( !str_contains( $root, WP_PATH ) ) { |
| 27 |
$root = WP_PATH . $root; |
| 28 |
} |
| 29 |
$root .= '/'; |
| 30 |
$root = wp_normalize_path( $root ); |
| 31 |
$excluded = [ |
| 32 |
'dirs' => LocalFileSystem::excludedDirs(), |
| 33 |
'files' => LocalFileSystem::excludedFiles(), |
| 34 |
]; |
| 35 |
return [ |
| 36 |
'root' => $root, |
| 37 |
'separator' => '/', |
| 38 |
'excluded_dirs' => ( !empty( $excluded['dirs'] ) ? $excluded['dirs'] : [] ), |
| 39 |
'excluded_files' => ( !empty( $excluded['files'] ) ? $excluded['files'] : [] ), |
| 40 |
'config' => [], |
| 41 |
'adapter' => function () use($root) { |
| 42 |
$permissions = [ |
| 43 |
'file' => [ |
| 44 |
'public' => ( defined( 'FS_CHMOD_FILE' ) ? FS_CHMOD_FILE : (( fileperms( WP_PATH . '/index.php' ) ? 0644 : 0777 )) ), |
| 45 |
'private' => 0600, |
| 46 |
], |
| 47 |
'dir' => [ |
| 48 |
'public' => ( defined( 'FS_CHMOD_DIR' ) ? FS_CHMOD_DIR : (( fileperms( WP_PATH ) ? 0755 : 0777 )) ), |
| 49 |
'private' => 0700, |
| 50 |
], |
| 51 |
]; |
| 52 |
global $wp_filesystem; |
| 53 |
$use_wp_filesystem = false; |
| 54 |
// Try and use WP filesystem |
| 55 |
if ( function_exists( 'request_filesystem_credentials' ) ) { |
| 56 |
if ( defined( 'FS_METHOD' ) ) { |
| 57 |
if ( !defined( 'WPIDE_FS_METHOD_FORCED_ELSEWHERE' ) ) { |
| 58 |
define( 'WPIDE_FS_METHOD_FORCED_ELSEWHERE', FS_METHOD ); |
| 59 |
} |
| 60 |
} else { |
| 61 |
define( 'FS_METHOD', 'direct' ); |
| 62 |
} |
| 63 |
ob_start(); |
| 64 |
$credentials = request_filesystem_credentials( '', FS_METHOD ); |
| 65 |
ob_end_clean(); |
| 66 |
$use_wp_filesystem = !empty( $wp_filesystem ) && wp_filesystem( $credentials ) === true; |
| 67 |
} |
| 68 |
if ( $use_wp_filesystem ) { |
| 69 |
return new WPFileSystem( |
| 70 |
$root, |
| 71 |
$wp_filesystem, |
| 72 |
1, |
| 73 |
$permissions |
| 74 |
); |
| 75 |
} else { |
| 76 |
return new DefaultFileSystem( |
| 77 |
$root, |
| 78 |
LOCK_EX, |
| 79 |
1, |
| 80 |
$permissions |
| 81 |
); |
| 82 |
} |
| 83 |
}, |
| 84 |
]; |
| 85 |
} |
| 86 |
|
| 87 |
public static function getRootDir() { |
| 88 |
return AppConfig::get( 'file.root', '/' ); |
| 89 |
} |
| 90 |
|
| 91 |
public static function advancedModeEnabled() : bool { |
| 92 |
$advanced_mode = (bool) AppConfig::get( 'file.advanced_mode', false ); |
| 93 |
if ( $advanced_mode ) { |
| 94 |
AppConfig::update( 'file.advanced_mode', false ); |
| 95 |
} |
| 96 |
$rootDefault = AppConfig::getField( 'file.root.default' ); |
| 97 |
if ( self::isRootExcluded() ) { |
| 98 |
AppConfig::update( 'file.root', $rootDefault ); |
| 99 |
} |
| 100 |
return false; |
| 101 |
} |
| 102 |
|
| 103 |
public static function excludedEntries( $type ) : array { |
| 104 |
$entries = AppConfig::get( 'file.filter_entries', [] ); |
| 105 |
$entries = ( is_array( $entries ) ? $entries : [] ); |
| 106 |
return array_filter( $entries, function ( $entry ) use($type) { |
| 107 |
if ( $type === 'dir' ) { |
| 108 |
return substr( $entry, -1 ) === '/'; |
| 109 |
} else { |
| 110 |
return substr( $entry, -1 ) !== '/'; |
| 111 |
} |
| 112 |
} ); |
| 113 |
} |
| 114 |
|
| 115 |
public static function excludedDirs( $forceSafeMode = false ) : array { |
| 116 |
$user_excluded_dirs = self::excludedEntries( 'dir' ); |
| 117 |
$user_excluded_dirs = array_merge( [IMAGE_DATA_DIR, TMP_DIR], $user_excluded_dirs ); |
| 118 |
if ( $forceSafeMode || !self::advancedModeEnabled() ) { |
| 119 |
$user_excluded_dirs = array_merge( [ |
| 120 |
DIR, |
| 121 |
rtrim( DIR, '/' ) . '-pro/', |
| 122 |
wp_normalize_path( WP_PLUGIN_DIR . '/wpide/' ), |
| 123 |
wp_normalize_path( WP_PLUGIN_DIR . '/wpide-pro/' ), |
| 124 |
wp_normalize_path( WP_PATH . '/wp-admin/' ), |
| 125 |
wp_normalize_path( WP_PATH . '/wp-includes/' ) |
| 126 |
], $user_excluded_dirs ); |
| 127 |
} |
| 128 |
return $user_excluded_dirs; |
| 129 |
} |
| 130 |
|
| 131 |
public static function excludedFiles( $forceSafeMode = false ) : array { |
| 132 |
$user_excluded_files = self::excludedEntries( 'file' ); |
| 133 |
$user_excluded_files = array_merge( [CONTENT_DIR . '/' . FATAL_ERROR_DROPIN], $user_excluded_files ); |
| 134 |
if ( $forceSafeMode || !self::advancedModeEnabled() ) { |
| 135 |
$user_excluded_files = array_merge( [wp_normalize_path( WP_PATH . '/wp-*.php' ), wp_normalize_path( WP_PATH . '/index.php' ), wp_normalize_path( WP_PATH . '/xmlrpc.php' )], $user_excluded_files ); |
| 136 |
} |
| 137 |
return $user_excluded_files; |
| 138 |
} |
| 139 |
|
| 140 |
public static function isDirExcluded( $path ) : bool { |
| 141 |
if ( $path !== '/' ) { |
| 142 |
$path = wp_normalize_path( WP_PATH . '/' . $path . '/' ); |
| 143 |
foreach ( self::excludedDirs( true ) as $excluded ) { |
| 144 |
if ( str_contains( $path, $excluded ) ) { |
| 145 |
return true; |
| 146 |
} |
| 147 |
} |
| 148 |
} |
| 149 |
return false; |
| 150 |
} |
| 151 |
|
| 152 |
public static function isRootExcluded() : bool { |
| 153 |
$root = self::getRootDir(); |
| 154 |
return self::isDirExcluded( $root ); |
| 155 |
} |
| 156 |
|
| 157 |
} |
| 158 |
|