$file ) { if ( in_array( basename( $file ), array( '.', '..' ) ) ) { unset( $files[$index] ); } } sort( $files ); return $files; } } return new WP_Error( 'itsec-lib-directory-read-cannot-read', sprintf( __( '%s could not be read due to an unknown error.', 'better-wp-security' ), $dir ) ); } /** * Determine if the supplied directory exists. * * @since 1.15.0 * * @param string $dir Full path to the directory to test. * @return bool|WP_Error Boolean true if it exists, false if it does not */ public static function is_dir( $dir ) { $dir = rtrim( $dir, '/' ); if ( empty( $dir ) ) { return true; } // phpcs:ignore -- Have Tide ignore the following line. We use arguments that don't exist in early versions, but these versions ignore the arguments. @clearstatcache( true, $dir ); return @is_dir( $dir ); } /** * Create the supplied directory. * * @since 1.15.0 * * @param string $dir Full path to the directory to create. * @return bool|WP_Error Boolean true if it is created successfully, WP_Error object otherwise. */ public static function create( $dir ) { $dir = rtrim( $dir, '/' ); if ( self::is_dir( $dir ) ) { self::add_file_listing_protection( $dir ); return true; } if ( ITSEC_Lib_File::exists( $dir ) ) { return new WP_Error( 'itsec-lib-directory-create-file-exists', sprintf( __( 'The directory %s could not be created as a file with that name already exists.', 'better-wp-security' ), $dir ) ); } if ( ! ITSEC_Lib_Utility::is_callable_function( 'mkdir' ) ) { return new WP_Error( 'itsec-lib-directory-create-mkdir-is-disabled', sprintf( __( 'The directory %s could not be created as the mkdir() function is disabled. This is a system configuration issue.', 'better-wp-security' ), $dir ) ); } $parent = dirname( $dir ); while ( ! empty( $parent ) && ! self::is_dir( $parent ) && dirname( $parent ) !== $parent ) { $parent = dirname( $parent ); } if ( empty( $parent ) ) { return new WP_Error( 'itsec-lib-directory-create-unable-to-find-parent', sprintf( __( 'The directory %s could not be created as an existing parent directory could not be found.', 'better-wp-security' ), $dir ) ); } $perms = self::get_permissions( $parent ); if ( ! is_int( $perms ) ) { $perms = 0755; } $cached_umask = umask( 0 ); $result = @mkdir( $dir, $perms, true ); umask( $cached_umask ); if ( $result ) { self::add_file_listing_protection( $dir ); return true; } return new WP_Error( 'itsec-lib-directory-create-failed', sprintf( __( 'The directory %s could not be created due to an unknown error. This could be due to a permissions issue.', 'better-wp-security' ), $dir ) ); } /** * Recursively remove the supplied directory. * * @since 1.15.0 * * @return bool|WP_Error Boolean true on success or a WP_Error object if an error occurs. */ public static function remove( $dir ) { if ( ! ITSEC_Lib_File::exists( $dir ) ) { return true; } if ( ! ITSEC_Lib_Utility::is_callable_function( 'rmdir' ) ) { return new WP_Error( 'itsec-lib-directory-remove-rmdir-is-disabled', sprintf( __( 'The directory %s could not be removed as the rmdir() function is disabled. This is a system configuration issue.', 'better-wp-security' ), $dir ) ); } $files = self::read( $dir ); if ( is_wp_error( $files ) ) { return new WP_Error( 'itsec-lib-directory-remove-read-error', sprintf( __( 'Unable to remove %1$s due to the following error: %2$s', 'better-wp-security' ), $dir, $files->get_error_message() ) ); } foreach ( $files as $file ) { if ( ITSEC_Lib_File::is_file( $file ) ) { ITSEC_Lib_File::remove( $file ); } else if ( self::is_dir( $file ) ) { self::remove( $file ); } } $result = rmdir( $dir ); // phpcs:ignore -- Have Tide ignore the following line. We use arguments that don't exist in early versions, but these versions ignore the arguments. @clearstatcache( true, $dir ); if ( $result ) { return true; } return new WP_Error( 'itsec-lib-directory-remove-unknown-error', sprintf( __( 'Unable to remove %s due to an unknown error.', 'better-wp-security' ), $dir ) ); } /** * Test to see if the requested directory is writable. * * @since 2.3.0 * * @param string $dir Full path to the directory to test. * @return bool True if the directory is writable, false otherwise. */ public static function is_writable( $dir ) { $dir = rtrim( $dir, '/' ); if ( ! self::is_dir( $dir ) ) { return false; } $test_count = 0; do { $test_file = 'itsec-test-file-' . wp_generate_password( 10, false ) . '.txt'; } while ( $test_count++ < 10 && ITSEC_Lib_File::exists( "$dir/$test_file" ) ); if ( ITSEC_Lib_File::exists( "$dir/$test_file" ) ) { return false; } $result = ITSEC_Lib_File::write( "$dir/$test_file", __( 'This is a test file generated by iThemes Security. It can be removed.', 'better-wp-security' ) ); ITSEC_Lib_File::remove( "$dir/$test_file" ); if ( true === $result ) { return $result; } return false; } /** * Add an index.php file to the directory to prevent file listing. * * @since 2.3.0 * * @param string $dir Full path to the directory to protect. * @return bool|WP_Error Boolean true if the file could be created or already exists, WP_Error object otherwise. */ public static function add_file_listing_protection( $dir ) { $dir = rtrim( $dir, '/' ); if ( ! self::is_dir( $dir ) ) { return new WP_Error( 'itsec-lib-directory-add-file-listing-protection-directory-does-not-exist', sprintf( __( 'The directory %s could not be protected from file listing as the directory does not exist.', 'better-wp-security' ), $dir ) ); } if ( ITSEC_Lib_File::exists( "$dir/index.php" ) ) { return true; } return ITSEC_Lib_File::write( "$dir/index.php", "