installed plugin Infinite Uploads
version 2.0.8
This commit is contained in:
@ -0,0 +1,260 @@
|
||||
<?php
|
||||
/**
|
||||
* Lists files using a Breadth-First search algorithm to allow for time limits and resume across multiple requests.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Infinite_Uploads_Filelist
|
||||
*/
|
||||
class Infinite_Uploads_Filelist {
|
||||
|
||||
public $is_done = false;
|
||||
public $paths_left = [];
|
||||
public $file_count = 0;
|
||||
public $file_list = [];
|
||||
public $exclusions = [
|
||||
'/et-cache/',
|
||||
'/et_temp/',
|
||||
'/imports/',
|
||||
'/cache/',
|
||||
'/wp-defender/',
|
||||
'.DS_Store',
|
||||
];
|
||||
protected $root_path;
|
||||
protected $timeout;
|
||||
protected $start_time;
|
||||
protected $instance;
|
||||
protected $insert_rows = 500;
|
||||
|
||||
/**
|
||||
* Infinite_Uploads_Filelist constructor.
|
||||
*
|
||||
* @param string $root_path The full path of the directory to iterate.
|
||||
* @param float $timeout Timeout in seconds.
|
||||
* @param array $paths_left Provide as returned if continuing the filelist after a timeout.
|
||||
*/
|
||||
public function __construct( $root_path, $timeout = 25.0, $paths_left = [] ) {
|
||||
$this->root_path = rtrim( $root_path, '/' ); //expected no trailing slash.
|
||||
$this->timeout = $timeout;
|
||||
$this->paths_left = $paths_left;
|
||||
$this->instance = Infinite_Uploads::get_instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs over the site's files.
|
||||
*/
|
||||
public function start() {
|
||||
global $wpdb;
|
||||
$this->start_time = microtime( true );
|
||||
$this->file_count = 0;
|
||||
$this->file_list = [];
|
||||
|
||||
// If just starting reset the local DB list storage
|
||||
if ( empty( $this->paths_left ) ) {
|
||||
//TRUNCATE is fastest, try it first
|
||||
$result = $wpdb->query( "TRUNCATE TABLE {$wpdb->base_prefix}infinite_uploads_files" );
|
||||
//Sometimes hosts don't give the DB user TRUNCATE permissions, so DELETE all if we have to.
|
||||
if ( false === $result ) {
|
||||
$wpdb->query( "DELETE FROM {$wpdb->base_prefix}infinite_uploads_files WHERE 1" );
|
||||
}
|
||||
|
||||
update_site_option( 'iup_files_scanned', [
|
||||
'files_started' => time(),
|
||||
'files_finished' => false,
|
||||
'compare_started' => false,
|
||||
'compare_finished' => false,
|
||||
'sync_started' => false,
|
||||
'sync_finished' => false,
|
||||
'download_started' => false,
|
||||
'download_finished' => false,
|
||||
] );
|
||||
}
|
||||
|
||||
$this->get_files();
|
||||
|
||||
$this->flush_to_db();
|
||||
|
||||
if ( empty( $this->paths_left ) ) {
|
||||
// So we are done. Say so.
|
||||
$this->is_done = true;
|
||||
|
||||
$progress = get_site_option( 'iup_files_scanned' );
|
||||
$progress['files_finished'] = time();
|
||||
update_site_option( 'iup_files_scanned', $progress );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a breadth-first iteration on all files and gathers the relevant info for each one.
|
||||
*
|
||||
* @todo test what happens if some files have no read permissions.
|
||||
*/
|
||||
protected function get_files() {
|
||||
|
||||
$paths = ( empty( $this->paths_left ) ) ? [ $this->root_path ] : $this->paths_left;
|
||||
|
||||
while ( ! empty( $paths ) ) {
|
||||
$path = array_pop( $paths );
|
||||
|
||||
// Skip ".." items.
|
||||
if ( preg_match( '/\.\.([\/\\\\]|$)/', $path ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( 0 !== strpos( $path, $this->root_path ) ) {
|
||||
// Build the absolute path in case it's not the first iteration.
|
||||
$path = rtrim( $this->root_path, '/' ) . $path;
|
||||
}
|
||||
|
||||
if ( $this->is_excluded( $path ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$contents = defined( 'GLOB_BRACE' )
|
||||
? glob( trailingslashit( $path ) . '{,.}[!.,!..]*', GLOB_BRACE )
|
||||
: glob( trailingslashit( $path ) . '[!.,!..]*' );
|
||||
|
||||
foreach ( $contents as $item ) {
|
||||
$file = [];
|
||||
if ( is_link( $item ) || $this->is_excluded( $item ) ) {
|
||||
continue;
|
||||
} elseif ( is_file( $item ) ) {
|
||||
if ( is_readable( $item ) ) {
|
||||
$file = $this->get_file_info( $item );
|
||||
} else {
|
||||
$file = null;
|
||||
error_log( sprintf( '[INFINITE_UPLOADS Filelist Error] %s could not be read for syncing', $item ) );
|
||||
}
|
||||
|
||||
$file['name'] = $this->relative_path( $item );
|
||||
|
||||
$this->add_file( $file );
|
||||
} elseif ( is_dir( $item ) ) {
|
||||
if ( ! in_array( $item, $paths, true ) ) {
|
||||
$paths[] = $this->relative_path( $item );
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->paths_left = $paths;
|
||||
|
||||
// If we have exceed the imposed time limit, lets pause the iteration here.
|
||||
if ( $this->has_exceeded_timelimit() ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->is_done = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks path against excluded pattern.
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
*/
|
||||
protected function is_excluded( $path ) {
|
||||
/**
|
||||
* Filters the built in list of file/directory exclusions that should not be synced to the Infinite Uploads cloud. Be specific it's a simple strpos() search for the strings.
|
||||
*
|
||||
* @param {array} $exclusions A list of file or directory names in the format of `/do-not-sync-this-dir/` or `somefilename.ext`.
|
||||
*
|
||||
* @return {array} A list of file or directory names in the format of `/do-not-sync-this-dir/` or `somefilename.ext`.
|
||||
* @since 1.0
|
||||
* @hook infinite_uploads_sync_exclusions
|
||||
*
|
||||
*/
|
||||
$exclusions = apply_filters( 'infinite_uploads_sync_exclusions', $this->exclusions );
|
||||
foreach ( $exclusions as $string ) {
|
||||
if ( false !== strpos( $path, $string ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks file health and returns as many info as it can.
|
||||
*
|
||||
* @param string $item The file to be investigated.
|
||||
*
|
||||
* @return mixed File info or false for failure.
|
||||
*/
|
||||
protected function get_file_info( $item ) {
|
||||
$file = [];
|
||||
$file['mtime'] = filemtime( $item );
|
||||
//$file['md5'] = md5_file( $item );
|
||||
$file['size'] = filesize( $item );
|
||||
$file['type'] = $this->instance->get_file_type( $item );
|
||||
|
||||
if ( empty( $file['mtime'] ) && empty( $file['size'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns rel path of file/dir, relative to site root.
|
||||
*
|
||||
* @param string $item File's absolute path.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function relative_path( $item ) {
|
||||
// Retrieve the relative to the site root path of the file.
|
||||
$pos = strpos( $item, $this->root_path );
|
||||
if ( 0 === $pos ) {
|
||||
return substr_replace( $item, '', $pos, strlen( $this->root_path ) );
|
||||
}
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add file details to internal storage and the db.
|
||||
*/
|
||||
protected function add_file( $file ) {
|
||||
$this->file_list[] = $file;
|
||||
$this->file_count ++;
|
||||
if ( count( $this->file_list ) >= $this->insert_rows ) {
|
||||
$this->flush_to_db();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the queued file list to DB storage.
|
||||
*/
|
||||
protected function flush_to_db() {
|
||||
global $wpdb;
|
||||
|
||||
if ( count( $this->file_list ) ) {
|
||||
$values = [];
|
||||
foreach ( $this->file_list as $file ) {
|
||||
$values[] = $wpdb->prepare( "(%s,%d,%d,%s,0)", $file['name'], $file['size'], $file['mtime'], $file['type'] );
|
||||
}
|
||||
|
||||
$query = "INSERT INTO {$wpdb->base_prefix}infinite_uploads_files (file, size, modified, type, errors) VALUES ";
|
||||
$query .= implode( ",\n", $values );
|
||||
$query .= " ON DUPLICATE KEY UPDATE size = VALUES(size), modified = VALUES(modified), type = VALUES(type), errors = 0";
|
||||
if ( $wpdb->query( $query ) ) {
|
||||
$this->file_list = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if current iteration has exceeded the given time limit.
|
||||
*
|
||||
* @return bool True if we have exceeded the time limit, false if we haven't.
|
||||
*/
|
||||
protected function has_exceeded_timelimit() {
|
||||
$current_time = microtime( true );
|
||||
$time_diff = number_format( $current_time - $this->start_time, 2 );
|
||||
|
||||
$has_exceeded_timelimit = ! empty( $this->timeout ) && ( $time_diff > $this->timeout );
|
||||
|
||||
return $has_exceeded_timelimit;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user