Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,8 @@ env:
- WP_TRAVISCI=travis:phpunit
matrix:
include:
- php: 7.1
env: WP_TRAVISCI=travis:js
- php: 7.2
- php: 7.1
- php: 7.0
- php: 5.6
- php: 5.6
env: WP_TRAVIS_OBJECT_CACHE=true
services: memcached
- php: 5.5
- php: 5.4
- php: 5.3
dist: precise
- php: 5.2
Expand Down
42 changes: 30 additions & 12 deletions src/wp-admin/includes/file.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,35 +120,53 @@ function get_home_path() {
* The depth of the recursiveness can be controlled by the $levels param.
*
* @since 2.6.0
* @since 4.9.0 Added the `$exclusions` parameter.
*
* @param string $folder Optional. Full path to folder. Default empty.
* @param int $levels Optional. Levels of folders to follow, Default 100 (PHP Loop limit).
* @param array $exclusions Optional. List of folders and files to skip.
* @return bool|array False on failure, Else array of files
*/
function list_files( $folder = '', $levels = 100 ) {
if ( empty($folder) )
function list_files( $folder = '', $levels = 100, $exclusions = array() ) {
if ( empty( $folder ) ) {
return false;
}

$folder = trailingslashit( $folder );

if ( ! $levels )
if ( ! $levels ) {
return false;
}

$files = array();
if ( $dir = @opendir( $folder ) ) {
while (($file = readdir( $dir ) ) !== false ) {
if ( in_array($file, array('.', '..') ) )

$dir = @opendir( $folder );
if ( $dir ) {
while ( ( $file = readdir( $dir ) ) !== false ) {
// Skip current and parent folder links.
if ( in_array( $file, array( '.', '..' ), true ) ) {
continue;
}

// Skip hidden and excluded files.
if ( '.' === $file[0] || in_array( $file, $exclusions, true ) ) {
continue;
if ( is_dir( $folder . '/' . $file ) ) {
$files2 = list_files( $folder . '/' . $file, $levels - 1);
if ( $files2 )
}

if ( is_dir( $folder . $file ) ) {
$files2 = list_files( $folder . $file, $levels - 1 );
if ( $files2 ) {
$files = array_merge($files, $files2 );
else
$files[] = $folder . '/' . $file . '/';
} else {
$files[] = $folder . $file . '/';
}
} else {
$files[] = $folder . '/' . $file;
$files[] = $folder . $file;
}
}
}
@closedir( $dir );

return $files;
}

Expand Down
60 changes: 34 additions & 26 deletions src/wp-admin/includes/plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -190,35 +190,43 @@ function _get_plugin_data_markup_translate( $plugin_file, $plugin_data, $markup
* @param string $plugin Path to the main plugin file from plugins directory.
* @return array List of files relative to the plugin root.
*/
function get_plugin_files($plugin) {
function get_plugin_files( $plugin ) {
$plugin_file = WP_PLUGIN_DIR . '/' . $plugin;
$dir = dirname($plugin_file);
$plugin_files = array($plugin);
if ( is_dir($dir) && $dir != WP_PLUGIN_DIR ) {
$plugins_dir = @ opendir( $dir );
if ( $plugins_dir ) {
while (($file = readdir( $plugins_dir ) ) !== false ) {
if ( substr($file, 0, 1) == '.' )
continue;
if ( is_dir( $dir . '/' . $file ) ) {
$plugins_subdir = @ opendir( $dir . '/' . $file );
if ( $plugins_subdir ) {
while (($subfile = readdir( $plugins_subdir ) ) !== false ) {
if ( substr($subfile, 0, 1) == '.' )
continue;
$plugin_files[] = plugin_basename("$dir/$file/$subfile");
}
@closedir( $plugins_subdir );
}
} else {
if ( plugin_basename("$dir/$file") != $plugin )
$plugin_files[] = plugin_basename("$dir/$file");
}
}
@closedir( $plugins_dir );
}
$dir = dirname( $plugin_file );

$data = get_plugin_data( $plugin_file );
$label = isset( $data['Version'] )
? sanitize_key( 'files_' . $plugin . '-' . $data['Version'] )
: sanitize_key( 'files_' . $plugin );
$transient_key = substr( $label, 0, 29 ) . md5( $label );

$plugin_files = get_transient( $transient_key );
if ( false !== $plugin_files ) {
return $plugin_files;
}

$plugin_files = array( plugin_basename( $plugin_file ) );

if ( is_dir( $dir ) && WP_PLUGIN_DIR !== $dir ) {

/**
* Filters the array of excluded directories and files while scanning the folder.
*
* @since 4.9.0
*
* @param array $exclusions Array of excluded directories and files.
*/
$exclusions = (array) apply_filters( 'plugin_files_exclusions', array( 'CVS', 'node_modules', 'vendor', 'bower_components' ) );

$list_files = list_files( $dir, 100, $exclusions );
$list_files = array_map( 'plugin_basename', $list_files );

$plugin_files = array_merge( $plugin_files, $list_files );
$plugin_files = array_values( array_unique( $plugin_files ) );
}

set_transient( $transient_key, $plugin_files, HOUR_IN_SECONDS );

return $plugin_files;
}

Expand Down
6 changes: 3 additions & 3 deletions src/wp-admin/theme-editor.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,16 +75,16 @@
foreach ( $file_types as $type ) {
switch ( $type ) {
case 'php':
$allowed_files += $theme->get_files( 'php', 1 );
$allowed_files += $theme->get_files( 'php', -1 );
$has_templates = ! empty( $allowed_files );
break;
case 'css':
$style_files = $theme->get_files( 'css' );
$style_files = $theme->get_files( 'css', -1 );
$allowed_files['style.css'] = $style_files['style.css'];
$allowed_files += $style_files;
break;
default:
$allowed_files += $theme->get_files( $type );
$allowed_files += $theme->get_files( $type, -1 );
break;
}
}
Expand Down
46 changes: 37 additions & 9 deletions src/wp-includes/class-wp-theme.php
Original file line number Diff line number Diff line change
Expand Up @@ -981,13 +981,38 @@ public function get_screenshot( $uri = 'uri' ) {
* @param int $depth Optional. How deep to search for files. Defaults to a flat scan (0 depth). -1 depth is infinite.
* @param bool $search_parent Optional. Whether to return parent files. Defaults to false.
* @return array Array of files, keyed by the path to the file relative to the theme's directory, with the values
* being absolute paths.
* being absolute paths.
*/
public function get_files( $type = null, $depth = 0, $search_parent = false ) {
$files = (array) self::scandir( $this->get_stylesheet_directory(), $type, $depth );
// get and cache all theme files to start with.
$label = sanitize_key( 'files_' . $this->cache_hash . '-' . $this->get( 'Version' ) );
$transient_key = substr( $label, 0, 29 ) . md5( $label );

if ( $search_parent && $this->parent() )
$files += (array) self::scandir( $this->get_template_directory(), $type, $depth );
$all_files = get_transient( $transient_key );
if ( false === $all_files ) {
$all_files = (array) self::scandir( $this->get_stylesheet_directory(), null, -1 );

if ( $search_parent && $this->parent() ) {
$all_files += (array) self::scandir( $this->get_template_directory(), null, -1 );
}

set_transient( $transient_key, $all_files, HOUR_IN_SECONDS );
}

// Filter $all_files by $type & $depth.
$files = array();
if ( $type ) {
$type = (array) $type;
$_extensions = implode( '|', $type );
}
foreach ( $all_files as $key => $file ) {
if ( $depth >= 0 && substr_count( $key, '/' ) > $depth ) {
continue; // Filter by depth.
}
if ( ! $type || preg_match( '~\.(' . $_extensions . ')$~', $file ) ) { // Filter by type.
$files[ $key ] = $file;
}
}

return $files;
}
Expand Down Expand Up @@ -1107,37 +1132,40 @@ public function get_page_templates( $post = null, $post_type = 'page' ) {
* with `$relative_path`, with the values being absolute paths. False otherwise.
*/
private static function scandir( $path, $extensions = null, $depth = 0, $relative_path = '' ) {
if ( ! is_dir( $path ) )
if ( ! is_dir( $path ) ) {
return false;
}

if ( $extensions ) {
$extensions = (array) $extensions;
$_extensions = implode( '|', $extensions );
}

$relative_path = trailingslashit( $relative_path );
if ( '/' == $relative_path )
if ( '/' == $relative_path ) {
$relative_path = '';
}

$results = scandir( $path );
$files = array();

/**
* Filters the array of excluded directories and files while scanning theme folder.
*
* @since 4.7.4
* @since 4.7.4
*
* @param array $exclusions Array of excluded directories and files.
*/
$exclusions = (array) apply_filters( 'theme_scandir_exclusions', array( 'CVS', 'node_modules' ) );
$exclusions = (array) apply_filters( 'theme_scandir_exclusions', array( 'CVS', 'node_modules', 'vendor', 'bower_components' ) );

foreach ( $results as $result ) {
if ( '.' == $result[0] || in_array( $result, $exclusions, true ) ) {
continue;
}
if ( is_dir( $path . '/' . $result ) ) {
if ( ! $depth )
if ( ! $depth ) {
continue;
}
$found = self::scandir( $path . '/' . $result, $extensions, $depth - 1 , $relative_path . $result );
$files = array_merge_recursive( $files, $found );
} elseif ( ! $extensions || preg_match( '~\.(' . $_extensions . ')$~', $result ) ) {
Expand Down
25 changes: 25 additions & 0 deletions tests/phpunit/tests/admin/includesPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,31 @@ public function test_get_plugin_files_single() {
$this->assertEquals( array( $name ), get_plugin_files( $name ) );
}

/**
* @covers ::get_plugin_files
*/
public function test_get_plugin_files_folder() {
$plugin_dir = WP_PLUGIN_DIR . '/list_files_test_plugin';
@mkdir( $plugin_dir );
$plugin = $this->_create_plugin(null, 'list_files_test_plugin.php', $plugin_dir );

$sub_dir = trailingslashit( dirname( $plugin[1] ) ) . 'subdir';
@mkdir( $sub_dir );
@file_put_contents( $sub_dir . '/subfile.php', '<?php // Silence.' );

$plugin_files = get_plugin_files( plugin_basename( $plugin[1] ) );
$expected = array(
'list_files_test_plugin/list_files_test_plugin.php',
'list_files_test_plugin/subdir/subfile.php',
);
$this->assertEquals( $expected, $plugin_files );

unlink( $sub_dir . '/subfile.php' );
unlink( $plugin[1] );
rmdir( $sub_dir );
rmdir( $plugin_dir );
}

/**
* @covers ::get_mu_plugins
*/
Expand Down
20 changes: 20 additions & 0 deletions tests/phpunit/tests/functions/listFiles.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

/**
* Test list_files().
*
* @group functions.php
*/
class Tests_Functions_ListFiles extends WP_UnitTestCase {
public function test_list_files_returns_a_list_of_files() {
$admin_files = list_files( ABSPATH . 'wp-admin/' );
$this->assertInternalType( 'array', $admin_files );
$this->assertNotEmpty( $admin_files );
$this->assertContains( ABSPATH . 'wp-admin/index.php', $admin_files );
}

public function test_list_files_can_exclude_files() {
$admin_files = list_files( ABSPATH . 'wp-admin/', 100, array( 'index.php' ) );
$this->assertNotContains( ABSPATH . 'wp-admin/index.php', $admin_files );
}
}