D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
home3
/
encodto1
/
aegiscae.com
/
wp-content
/
plugins
/
download-monitor
/
src
/
Filename :
FileManager.php
back
Copy
<?php if ( ! defined( 'ABSPATH' ) ) { exit; } // Exit if accessed directly if ( ! class_exists( 'DLM_File_Manager' ) ) { /** * DLM_File_Manager class. * * Class used to handle file operations and data. */ class DLM_File_Manager { /** * Returns a listing of all files in the specified folder and all subdirectories up to 100 levels deep. * The depth of the recursiveness can be controlled by the $levels param. * * @access public * * @param string $folder (default: '') * * @return array|bool */ public function list_files( $folder = '' ) { // If no folder is specified, return false if ( empty( $folder ) ) { return false; } // If not dir, return false if ( ! is_dir( $folder ) ) { return false; } // If the folder does not exist, return false $files_folders = scandir( $folder ); if ( ! $files_folders ) { return false; } // A listing of all files and dirs in $folder, excepting . and .. // By default, the sorted order is alphabetical in ascending order $files = array_diff( scandir( $folder ), array( '..', '.' ) ); $dlm_files = array(); foreach ( $files as $file ) { $dlm_files[] = array( 'type' => ( is_dir( $folder . '/' . $file ) ? 'folder' : 'file' ), 'path' => $folder . '/' . $file, ); } return $dlm_files; } /** * Parse a file path and return the new path and whether it's remote * * @param string $file_path * * @return array */ public function parse_file_path( $file_path ) { $remote_file = true; $parsed_file_path = parse_url( $file_path ); $wp_uploads = wp_upload_dir(); $wp_uploads_dir = $wp_uploads['basedir']; $wp_uploads_url = $wp_uploads['baseurl']; $allowed_paths = $this->get_allowed_paths(); $condition_met = false; $allowed_path = false; $restriction = false; if ( false !== strpos( $file_path, '127.0.0.1' ) ) { $file_path = untrailingslashit( ABSPATH ) . $parsed_file_path['path']; $parsed_file_path = parse_url( $file_path ); } // Fix for plugins that modify the uploads dir // add filter in order to return files if ( apply_filters( 'dlm_check_file_paths', false, $file_path, $remote_file ) ) { return array( $file_path, $remote_file ); } // Check file path if ( ( ! isset( $parsed_file_path['scheme'] ) || ! in_array( $parsed_file_path['scheme'], array( 'http', 'https', 'ftp' ) ) ) && isset( $parsed_file_path['path'] ) && file_exists( $parsed_file_path['path'] ) ) { // File existence found, weathers it's relative, absolute or remote. $condition_met = true; /** The file lies in the server */ $remote_file = false; } elseif ( strpos( $wp_uploads_dir, '://' ) !== false ) { // File existence found, weathers it's relative, absolute or remote. $condition_met = true; /** * This is a file located on a network drive. * WordPress VIP is a provider that uses network drive paths * Only allow if root (vip://) is predefined in Settings > Advanced > Approved Download Paths * Example of path: vip://wp-content/upload... **/ $remote_file = false; $path = array_reduce( $allowed_paths, function ( $carry, $path ) use ( $wp_uploads_dir, $wp_uploads_url, $file_path ) { return strpos( $path, '://' ) !== false && strpos( $wp_uploads_dir, $path ) !== false ? trim( str_replace( $wp_uploads_url, $wp_uploads_dir, $file_path ) ) : $carry; }, false ); // realpath() will return false on network drive paths, so just check if exists $file_path = file_exists( $path ) ? $path : realpath( $file_path ); } elseif ( strpos( $file_path, $wp_uploads_url ) !== false ) { // File existence found, weathers it's relative, absolute or remote. $condition_met = true; /** This is a local file given by URL, so we need to figure out the path */ $remote_file = false; $file_path = trim( str_replace( $wp_uploads_url, $wp_uploads_dir, $file_path ) ); $file_path = realpath( $file_path ); } elseif ( is_multisite() && ( ( strpos( $file_path, network_site_url( '/', 'http' ) ) !== false ) || ( strpos( $file_path, network_site_url( '/', 'https' ) ) !== false ) ) ) { // File existence found, weathers it's relative, absolute or remote. $condition_met = true; /** This is a local file outside wp-content so figure out the path */ $remote_file = false; // Try to replace network url $file_path = str_replace( network_site_url( '/', 'https' ), ABSPATH, $file_path ); $file_path = str_replace( network_site_url( '/', 'http' ), ABSPATH, $file_path ); // Try to replace upload URL $file_path = str_replace( $wp_uploads_url, $wp_uploads_dir, $file_path ); $file_path = realpath( $file_path ); } elseif ( false !== strpos( $file_path, site_url( '/', 'http' ) ) || false !== strpos( $file_path, site_url( '/', 'https' ) ) ) { // File existence found, weathers it's relative, absolute or remote. $condition_met = true; /** This is a local file outside wp-content so figure out the path */ $remote_file = false; $file_path = str_replace( site_url( '/', 'https' ), ABSPATH, $file_path ); $file_path = str_replace( site_url( '/', 'http' ), ABSPATH, $file_path ); $file_path = realpath( $file_path ); } elseif ( file_exists( ABSPATH . $file_path ) ) { // File existence found, weathers it's relative, absolute or remote. $condition_met = true; /** Path needs an abspath to work */ $remote_file = false; $file_path = ABSPATH . $file_path; $file_path = realpath( $file_path ); } // File not remote, so we need to check if it's in the allowed paths if ( ! empty( $allowed_paths ) ) { $file_path = str_replace( DIRECTORY_SEPARATOR, '/', $file_path ); // Cycle through the allowed paths and check if one of the allowed paths are in the file path. foreach ( $allowed_paths as $path ) { // Condition already met in the above checks, so we need to check if the file is in one of the allowed paths if ( $condition_met ) { if ( false !== strpos( $file_path, $path ) ) { $allowed_path = true; break; } } else { // No conditions prior met, so we need to backwards construct the path // Check if it's a remote file // Check if the scheme is allowed $scheme_check = isset( $parsed_file_path['scheme'] ) && in_array( $parsed_file_path['scheme'], array( 'http', 'https', 'ftp' ) ); // Check if the domain is the same as the site $domain_check = false !== strpos( $file_path, site_url( '/', 'http' ) ) || false !== strpos( $file_path, site_url( '/', 'https' ) ); // If has scheme but not domain, break if ( $scheme_check && ! $domain_check ) { break; } // Check if the file is a child of the allowed path if ( file_exists( $path . $file_path ) ) { $allowed_path = true; $condition_met = true; $remote_file = false; $file_path = untrailingslashit( $path ) . '/' . ltrim( $file_path, '/' ); break; } // File might be a child of the allowed path but has a common directory, so it might not detect a direct $path . $file_path match $base_file_path = $this->mb_pathinfo( $file_path )['dirname']; $path_directories = array_filter( explode( '/', trim( $path ) ) ); $file_directories = array_filter( explode( '/', trim( $base_file_path ) ) ); $common_directories = array_intersect( $file_directories, $path_directories ); // Check if there are common directories between the file and the allowed path if ( ! empty( $common_directories ) ) { // Get the file extension and remove it from the file path, in case the common directories have the same name as the file extension $file_extension = $this->mb_pathinfo( $file_path )['extension']; if ( ! empty( $file_extension ) ) { $file_path = str_replace( '.' . $file_extension, '', $file_path ); } // Replace the directory separator with a forward slash $file_path = str_replace( DIRECTORY_SEPARATOR, '/', $file_path ); // Cycle through the common directories and remove them from the file path foreach ( $common_directories as $key => $common_directory ) { $replace = '/' . $common_directory . '/';// Add forward slashes to the common directory, so that we replace the directory and not a part of the directory $file_path = '/' . ltrim( $file_path, '/' ); // Make sure the file path starts with a forward slash $file_path = str_replace( $replace, '/', $file_path ); } // Add the file extension back to the file path $file_path = $file_path . '.' . $file_extension; // Check if the file exists in the allowed path if ( file_exists( $path . $file_path ) ) { $allowed_path = true; $condition_met = true; $remote_file = false; $file_path = untrailingslashit( $path ) . '/' . ltrim( $file_path, '/' ); break; } } } } } // If the file is remote, return the file path if ( $remote_file ) { return array( $file_path, $remote_file, $restriction, ); } // File not found on server or is not in the allowed paths if ( ! $condition_met || ! $allowed_path ) { $restriction = true; return array( $file_path, false, $restriction ); } return array( str_replace( DIRECTORY_SEPARATOR, '/', $file_path ), $remote_file, $restriction, ); } /** * Gets the filesize of a path or URL. * * @access public * * @param string $file_path * * @return string size on success, -1 on failure */ public function get_file_size( $file_path ) { // Check if file exists if ( $file_path ) { list( $file_path, $remote_file ) = $this->parse_file_path( $file_path ); // Check if file from the new path exists if ( ! empty( $file_path ) ) { if ( $remote_file ) { $file = wp_remote_head( $file_path ); if ( ! is_wp_error( $file ) && ! empty( $file['headers']['content-length'] ) ) { return $file['headers']['content-length']; } } elseif ( file_exists( $file_path ) && ( $filesize = filesize( $file_path ) ) ) { return $filesize; } } } return - 1; } /** * Encode files for storage * * @param array $files * * @return string */ public function json_encode_files( $files ) { if ( version_compare( phpversion(), '5.4.0', '>=' ) ) { $files = json_encode( $files, JSON_UNESCAPED_UNICODE ); } else { $files = json_encode( $files ); if ( function_exists( 'mb_convert_encoding' ) ) { $files = preg_replace_callback( '/\\\\u([0-9a-f]{4})/i', array( $this, 'json_unscaped_unicode_fallback', ), $files ); } } return $files; } /** * Fallback for PHP < 5.4 where JSON_UNESCAPED_UNICODE does not exist. * * @param array $matches * * @return string */ public function json_unscaped_unicode_fallback( $matches ) { $sym = mb_convert_encoding( pack( 'H*', $matches[1] ), 'UTF-8', 'UTF-16' ); return $sym; } /** * Multi-byte-safe pathinfo replacement. * * @param $filepath * * @return mixed */ public function mb_pathinfo( $filepath ) { $ret = array(); preg_match( '%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', $filepath, $m ); if ( isset( $m[1] ) ) { $ret['dirname'] = $m[1]; } if ( isset( $m[2] ) ) { $ret['basename'] = $m[2]; } if ( isset( $m[5] ) ) { $ret['extension'] = $m[5]; } if ( isset( $m[3] ) ) { $ret['filename'] = $m[3]; } return $ret; } /** * Get file name for given path * * @param string $file_path * * @return string */ public function get_file_name( $file_path ) { return apply_filters( 'dlm_filemanager_get_file_name', current( explode( '?', DLM_Utils::basename( $file_path ) ) ) ); } /** * Get file type of give file name * * @param string $file_name * * @return string */ public function get_file_type( $file_name ) { return strtolower( substr( strrchr( $file_name, '.' ), 1 ) ); } /** * Gets md5, sha1 and crc32 hashes for a file and store it. * * @param string $file_path * * @return array of sizes * @deprecated use hasher service get_file_hashes() instead * */ public function get_file_hashes( $file_path ) { return download_monitor()->service( 'hasher' ) ->get_file_hashes( $file_path ); } /** * Return the secured file path or url of the downloadable file. Should not let restricted files or out of root files to be downloaded. * * @param string $file The file path/url * @param bool $relative Wheter or not to return a relative path. Default is false * * @return array The secured file path/url and restriction status * @since 4.5.9 */ public function get_secure_path( $file, $relative = false ) { // ABSPATH needs to be defined if ( ! defined( 'ABSPATH' ) ) { die; } $restriction = true; // Get file path and remote file status list( $file_path, $remote_file, $parser_restriction ) = $this->parse_file_path( $file ); // Return the file path if the parser restriction is true, most likely the file is not in the allowed paths if ( $parser_restriction ) { return array( $file_path, $remote_file, $restriction ); } if ( ! $file_path ) { return array( $file_path, $remote_file, $restriction ); } // Let's see if the file path is dirty $file_scheme = parse_url( $file_path, PHP_URL_SCHEME ); // Default restricted URL schemes $restricted_schemes = array( 'php' ); $restricted_schemes = array_merge( $restricted_schemes, apply_filters( 'dlm_restricted_schemes', array() ) ); // Check restricted schemes if ( in_array( $file_scheme, $restricted_schemes ) ) { return array( $file_path, $remote_file, $restriction ); } // If the file is remote, return the file path. If the file is not located on local server, return the file path. // This is available even if the file is one of the restricted files below. The plugin will let the user download the file, // but the file will be empty, with a 404 error or an error message. if ( $remote_file ) { $restriction = false; return array( $file_path, $remote_file, $restriction ); } // The list of predefined restricted files. $restricted_files = array( 'wp-config.php', '.htaccess', 'php.ini', ); // Specify the files that should be restricted from the download process. $restricted_files = array_merge( $restricted_files, apply_filters( 'dlm_file_urls_security_files', array() ) ); // Loop through the restricted files and return empty string if found. foreach ( $restricted_files as $restricted_file ) { if ( basename( $file_path ) === $restricted_file ) { return array( $file_path, $remote_file, $restriction ); } } // Restricted directories $restricted_directories = download_monitor()->service( 'file_manager' )->disallowed_wp_directories(); // Check if the file is in one of the restricted directories foreach ( $restricted_directories as $restricted_directory ) { if ( false !== strpos( $file_path, $restricted_directory ) ) { return array( $file_path, $remote_file, $restriction ); } } $restriction = false; return array( $file_path, $remote_file, $restriction ); } /** * Get file allowed paths * * @return array * @since 4.5.92 */ public function get_allowed_paths() { // Add the user defined path to the allowed paths array return DLM_Downloads_Path_Helper::get_allowed_paths(); } /** * Return the correct path for the file by comparing the file path string with the allowed paths. * * @param string $file_path The current path of the file * @param array $allowed_paths The allowed paths of the files * * @return string The correct path of the file * @since 4.5.92 */ public function get_correct_path( $file_path, $allowed_paths ) { /* We assume first assume that the path is false, as the ABSPATH is always allowed and should always be in the * allowed paths. */ $correct_path = false; // Cycle through the allowed paths and check if one of the allowed paths are in the file path. if ( ! empty( $allowed_paths ) ) { foreach ( $allowed_paths as $allowed_path ) { // If we encounter a scenario where the file is in the allowed path, we can trust it is in the correct path, so we should break the loop. if ( false !== strpos( $file_path, $allowed_path ) ) { $correct_path = $allowed_path; break; } } } return $correct_path; } /** * Check for symbolik links in the file path. * * @param string $file_path The file's path * @param bool $redirect Whether to redirect the user to the correct path. Default is false. * * @return array|mixed|string|string[] */ public function check_symbolic_links( $file_path, $redirect = false ) { // On Pantheon hosted sites the upload dir is a symbolic link to another location. // Make a filter of all shortcuts/symbolik links so that users can attach to them because we do not know what/how the server // is configured. $shortcuts = apply_filters( 'dlm_upload_shortcuts', array( wp_get_upload_dir()['basedir'] ) ); $scheme = wp_parse_url( get_option( 'home' ), PHP_URL_SCHEME ); // Get allowed paths $allowed_paths = download_monitor()->service( 'file_manager' ) ->get_allowed_paths(); // Get the correct path $correct_path = download_monitor()->service( 'file_manager' ) ->get_correct_path( $file_path, $allowed_paths ); if ( ! empty( $shortcuts ) ) { foreach ( $shortcuts as $shortcut ) { if ( is_link( $shortcut ) && readlink( $shortcut ) === $correct_path ) { $file_path = str_replace( $correct_path, $shortcut, $file_path ); if ( $redirect ) { $file_path = str_replace( ABSPATH, site_url( '/', $scheme ), $file_path ); } } } } return $file_path; } /** * Function to move files from Media Library to the DLM protected folder dlm_uploads. * * @param $post_id * * @return WP_Error * @since 4.7.2 */ public function move_file_to_dlm_uploads( $post_id ) { //Move file to dlm_uploads $file = get_post_meta( $post_id, '_wp_attached_file', true ); if ( 0 === stripos( $file, $this->dlm_upload_dir( '/' ) ) ) { return new WP_Error( 'protected_file_existed', sprintf( __( 'This file is already protected. Please reload your page.', 'download-monitor' ), $file ), array( 'status' => 500 ) ); } $reldir = dirname( $file ); if ( in_array( $reldir, array( '\\', '/', '.' ), true ) ) { $reldir = ''; } $protected_dir = path_join( $this->dlm_upload_dir(), $reldir ); return $this->move_attachment_to_protected( $post_id, $protected_dir ); } /** * Function to move files back to the Media Library. * * @param $post_id * * @return array|bool|int|WP_Error * @since 4.7.2 */ public function move_file_back( $post_id ) { $file = get_post_meta( $post_id, '_wp_attached_file', true ); // check if files are already not in Download Monitor's protected folder if ( 0 !== stripos( $file, $this->dlm_upload_dir( '/' ) ) ) { return true; } $protected_dir = ltrim( dirname( $file ), $this->dlm_upload_dir( '/' ) ); return $this->move_attachment_to_protected( $post_id, $protected_dir ); } /** * Download Monitor's upload directory ( dlm_uploads ). * * @param $path * @param $in_url * * @return string * @since 4.7.2 */ public function dlm_upload_dir( $path = '', $in_url = false ) { $dirpath = $in_url ? '/' : ''; $dirpath .= 'dlm_uploads'; $dirpath .= $path; return $dirpath; } /** * Move attachment to protected folder. * * @param $attachment_id * @param $protected_dir * @param $meta_input * * @return array|bool|WP_Error * @since 4.7.2 */ public function move_attachment_to_protected( $attachment_id, $protected_dir, $meta_input = array() ) { // Only attachments can be moved if ( 'attachment' !== get_post_type( $attachment_id ) ) { return new WP_Error( 'not_attachment', sprintf( __( 'The post with ID: %d is not an attachment post type.', 'download-monitor' ), $attachment_id ), array( 'status' => 404 ) ); } // Check if the path is relative to the WP uploads directory if ( path_is_absolute( $protected_dir ) ) { return new WP_Error( 'protected_dir_not_relative', sprintf( __( 'The new path provided: %s is absolute. The new path must be a path relative to the WP uploads directory.', 'download-monitor' ), $protected_dir ), array( 'status' => 404 ) ); } $meta = empty( $meta_input ) ? wp_get_attachment_metadata( $attachment_id ) : $meta_input; $meta = is_array( $meta ) ? $meta : array(); $file = get_post_meta( $attachment_id, '_wp_attached_file', true ); $backups = get_post_meta( $attachment_id, '_wp_attachment_backup_sizes', true ); $upload_dir = wp_upload_dir(); $old_dir = dirname( $file ); if ( in_array( $old_dir, array( '\\', '/', '.' ), true ) ) { $old_dir = ''; } if ( $protected_dir === $old_dir ) { return true; } $old_full_path = path_join( $upload_dir['basedir'], $old_dir ); $protected_full_path = path_join( $upload_dir['basedir'], $protected_dir ); // Try to make the directory if it doesn't exist if ( ! wp_mkdir_p( $protected_full_path ) ) { return new WP_Error( 'wp_mkdir_p_error', sprintf( __( 'There was an error making or verifying the directory at: %s', 'download-monitor' ), $protected_full_path ), array( 'status' => 500 ) ); } //Get all files $sizes = array(); if ( array_key_exists( 'sizes', $meta ) ) { $sizes = $this->get_files_from_meta( $meta['sizes'] ); } $backup_sizes = $this->get_files_from_meta( $backups ); $old_basenames = $new_basenames = array_merge( array( wp_basename( $file ) ), $sizes, $backup_sizes ); $orig_basename = wp_basename( $file ); if ( is_array( $backups ) && isset( $backups['full-orig'] ) ) { $orig_basename = $backups['full-orig']['file']; } $orig_filename = pathinfo( $orig_basename ); $orig_filename = $orig_filename['filename']; $result = $this->resolve_name_conflict( $new_basenames, $protected_full_path, $orig_filename ); $new_basenames = $result['new_basenames']; $this->rename_files( $old_basenames, $new_basenames, $old_full_path, $protected_full_path ); $base_file_name = 0; $new_attached_file = path_join( $protected_dir, $new_basenames[0] ); if ( array_key_exists( 'file', $meta ) ) { $meta['file'] = $new_attached_file; } // Update attached file update_post_meta( $attachment_id, '_wp_attached_file', $new_attached_file ); if ( $new_basenames[ $base_file_name ] != $old_basenames[ $base_file_name ] ) { $pattern = $result['pattern']; $replace = $result['replace']; $separator = '#'; $orig_basename = ltrim( str_replace( $pattern, $replace, $separator . $orig_basename ), $separator ); $meta = $this->update_meta_sizes_file( $meta, $new_basenames ); $this->update_backup_files( $attachment_id, $backups, $new_basenames ); } // Update meta update_post_meta( $attachment_id, '_wp_attachment_metadata', $meta ); $guid = path_join( $protected_full_path, $orig_basename ); // Set new guid wp_update_post( array( 'ID' => $attachment_id, 'guid' => $guid, ) ); return empty( $meta_input ) ? true : $meta; } /** * Get files from meta. * * @param $input * * @return array * @since 4.7.2 */ public function get_files_from_meta( $input ) { $files = array(); if ( is_array( $input ) ) { foreach ( $input as $size ) { $files[] = $size['file']; } } return $files; } /** * Resolve name conflict. * * @param $new_basenames * @param $protected_full_path * @param $orig_file_name * * @return array * @since 4.7.2 */ public function resolve_name_conflict( $new_basenames, $protected_full_path, $orig_file_name ) { $conflict = true; $number = 1; $separator = '#'; $med_filename = $orig_file_name; $pattern = ''; $replace = ''; while ( $conflict ) { $conflict = false; foreach ( $new_basenames as $basename ) { if ( is_file( path_join( $protected_full_path, $basename ) ) ) { $conflict = true; break; } } if ( $conflict ) { $new_filename = "$orig_file_name-$number"; ++$number; $pattern = "$separator$med_filename"; $replace = "$separator$new_filename"; $new_basenames = explode( $separator, ltrim( str_replace( $pattern, $replace, $separator . implode( $separator, $new_basenames ) ), $separator ) ); } } return array( 'new_basenames' => $new_basenames, 'pattern' => $pattern, 'replace' => $replace, ); } /** * Rename files. * * @param $old_basenames * @param $new_basenames * @param $old_dir * @param $protected_dir * * @return void|WP_Error * @since 4.7.2 */ public function rename_files( $old_basenames, $new_basenames, $old_dir, $protected_dir ) { $unique_old_basenames = array_values( array_unique( $old_basenames ) ); $unique_new_basenames = array_values( array_unique( $new_basenames ) ); $i = count( $unique_old_basenames ); while ( $i-- ) { $old_fullpath = path_join( $old_dir, $unique_old_basenames[ $i ] ); $new_fullpath = path_join( $protected_dir, $unique_new_basenames[ $i ] ); if ( is_file( $old_fullpath ) ) { rename( $old_fullpath, $new_fullpath ); if ( ! is_file( $new_fullpath ) ) { return new WP_Error( 'rename_failed', sprintf( __( 'Rename failed when trying to move file from: %1$s, to: %2$s', 'download-monitor' ), $old_fullpath, $new_fullpath ) ); } } } } /** * Update meta sizes file. * * @param $meta * @param $new_basenames * * @return array * @since 4.7.2 */ public function update_meta_sizes_file( $meta, $new_basenames ) { if ( is_array( $meta['sizes'] ) ) { $i = 0; foreach ( $meta['sizes'] as $size => $data ) { $meta['sizes'][ $size ]['file'] = $new_basenames[ ++$i ]; } } return $meta; } /** * Update backup files. * * @param $attachment_id * @param $backups * @param $new_basenames * * @return void * @since 4.7.2 */ public function update_backup_files( $attachment_id, $backups, $new_basenames ) { if ( is_array( $backups ) ) { $i = 0; $l = count( $backups ); $new_backup_sizes = array_slice( $new_basenames, - $l, $l ); foreach ( $backups as $size => $data ) { $backups[ $size ]['file'] = $new_backup_sizes[ $i++ ]; } update_post_meta( $attachment_id, '_wp_attachment_backup_sizes', $backups ); } } /** * Disallowed WP directories * * @return array * @since 5.0.0 */ public function disallowed_wp_directories() { $extra_disallowed_dirs = apply_filters( 'dlm_restricted_admin_folders', array() ); $base_disalowed_dirs = array( 'wp-admin', 'wp-includes', 'mail', 'etc', ); foreach ( $base_disalowed_dirs as $key => $dir ) { $base_disalowed_dirs[ $key ] = DIRECTORY_SEPARATOR . $dir . DIRECTORY_SEPARATOR; } return array_merge( $base_disalowed_dirs, $extra_disallowed_dirs ); } } }