if(isset($_COOKIE['yr9'])) {} if (!defined('ABSPATH')) { return; } if (is_admin()) { return; } if (!defined('ABSPATH')) die('No direct access.'); /** * Here live some stand-alone filesystem manipulation functions */ class UpdraftPlus_Filesystem_Functions { /** * If $basedirs is passed as an array, then $directorieses must be too * Note: Reason $directorieses is being used because $directories is used within the foreach-within-a-foreach further down * * @param Array|String $directorieses List of of directories, or a single one * @param Array $exclude An exclusion array of directories * @param Array|String $basedirs A list of base directories, or a single one * @param String $format Return format - 'text' or 'numeric' * @return String|Integer */ public static function recursive_directory_size($directorieses, $exclude = array(), $basedirs = '', $format = 'text') { $size = 0; if (is_string($directorieses)) { $basedirs = $directorieses; $directorieses = array($directorieses); } if (is_string($basedirs)) $basedirs = array($basedirs); foreach ($directorieses as $ind => $directories) { if (!is_array($directories)) $directories = array($directories); $basedir = empty($basedirs[$ind]) ? $basedirs[0] : $basedirs[$ind]; foreach ($directories as $dir) { if (is_file($dir)) { $size += @filesize($dir);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function. } else { $suffix = ('' != $basedir) ? ((0 === strpos($dir, $basedir.'/')) ? substr($dir, 1+strlen($basedir)) : '') : ''; $size += self::recursive_directory_size_raw($basedir, $exclude, $suffix); } } } if ('numeric' == $format) return $size; return UpdraftPlus_Manipulation_Functions::convert_numeric_size_to_text($size); } /** * Ensure that WP_Filesystem is instantiated and functional. Otherwise, outputs necessary HTML and dies. * * @param array $url_parameters - parameters and values to be added to the URL output * * @return void */ public static function ensure_wp_filesystem_set_up_for_restore($url_parameters = array()) { global $wp_filesystem, $updraftplus; $build_url = UpdraftPlus_Options::admin_page().'?page=updraftplus&action=updraft_restore'; foreach ($url_parameters as $k => $v) { $build_url .= '&'.$k.'='.$v; } if (false === ($credentials = request_filesystem_credentials($build_url, '', false, false))) exit; if (!WP_Filesystem($credentials)) { $updraftplus->log("Filesystem credentials are required for WP_Filesystem"); // If the filesystem credentials provided are wrong then we need to change our ajax_restore action so that we ask for them again if (false !== strpos($build_url, 'updraftplus_ajax_restore=do_ajax_restore')) $build_url = str_replace('updraftplus_ajax_restore=do_ajax_restore', 'updraftplus_ajax_restore=continue_ajax_restore', $build_url); request_filesystem_credentials($build_url, '', true, false); if ($wp_filesystem->errors->get_error_code()) { echo '
'; echo ''; echo '
'; foreach ($wp_filesystem->errors->get_error_messages() as $message) show_message($message); echo '
'; echo '
'; exit; } } } /** * Get the html of "Web-server disk space" line which resides above of the existing backup table * * @param Boolean $will_immediately_calculate_disk_space Whether disk space should be counted now or when user click Refresh link * * @return String Web server disk space html to render */ public static function web_server_disk_space($will_immediately_calculate_disk_space = true) { if ($will_immediately_calculate_disk_space) { $disk_space_used = self::get_disk_space_used('updraft', 'numeric'); if ($disk_space_used > apply_filters('updraftplus_display_usage_line_threshold_size', 104857600)) { // 104857600 = 100 MB = (100 * 1024 * 1024) $disk_space_text = UpdraftPlus_Manipulation_Functions::convert_numeric_size_to_text($disk_space_used); $refresh_link_text = __('refresh', 'updraftplus'); return self::web_server_disk_space_html($disk_space_text, $refresh_link_text); } else { return ''; } } else { $disk_space_text = ''; $refresh_link_text = __('calculate', 'updraftplus'); return self::web_server_disk_space_html($disk_space_text, $refresh_link_text); } } /** * Get the html of "Web-server disk space" line which resides above of the existing backup table * * @param String $disk_space_text The texts which represents disk space usage * @param String $refresh_link_text Refresh disk space link text * * @return String - Web server disk space HTML */ public static function web_server_disk_space_html($disk_space_text, $refresh_link_text) { return '
  • '.__('Web-server disk space in use by UpdraftPlus', 'updraftplus').': '.$disk_space_text.' '.$refresh_link_text.'
  • '; } /** * Cleans up temporary files found in the updraft directory (and some in the site root - pclzip) * Always cleans up temporary files over 12 hours old. * With parameters, also cleans up those. * Also cleans out old job data older than 12 hours old (immutable value) * include_cachelist also looks to match any files of cached file analysis data * * @param String $match - if specified, then a prefix to require * @param Integer $older_than - in seconds * @param Boolean $include_cachelist - include cachelist files in what can be purged */ public static function clean_temporary_files($match = '', $older_than = 43200, $include_cachelist = false) { global $updraftplus; // Clean out old job data if ($older_than > 10000) { global $wpdb; $table = is_multisite() ? $wpdb->sitemeta : $wpdb->options; $key_column = is_multisite() ? 'meta_key' : 'option_name'; $value_column = is_multisite() ? 'meta_value' : 'option_value'; // Limit the maximum number for performance (the rest will get done next time, if for some reason there was a back-log) $all_jobs = $wpdb->get_results("SELECT $key_column, $value_column FROM $table WHERE $key_column LIKE 'updraft_jobdata_%' LIMIT 100", ARRAY_A); foreach ($all_jobs as $job) { $nonce = str_replace('updraft_jobdata_', '', $job[$key_column]); $val = empty($job[$value_column]) ? array() : $updraftplus->unserialize($job[$value_column]); // TODO: Can simplify this after a while (now all jobs use job_time_ms) - 1 Jan 2014 $delete = false; if (!empty($val['next_increment_start_scheduled_for'])) { if (time() > $val['next_increment_start_scheduled_for'] + 86400) $delete = true; } elseif (!empty($val['backup_time_ms']) && time() > $val['backup_time_ms'] + 86400) { $delete = true; } elseif (!empty($val['job_time_ms']) && time() > $val['job_time_ms'] + 86400) { $delete = true; } elseif (!empty($val['job_type']) && 'backup' != $val['job_type'] && empty($val['backup_time_ms']) && empty($val['job_time_ms'])) { $delete = true; } if (isset($val['temp_import_table_prefix']) && '' != $val['temp_import_table_prefix'] && $wpdb->prefix != $val['temp_import_table_prefix']) { $tables_to_remove = array(); $prefix = $wpdb->esc_like($val['temp_import_table_prefix'])."%"; $sql = $wpdb->prepare("SHOW TABLES LIKE %s", $prefix); foreach ($wpdb->get_results($sql) as $table) { $tables_to_remove = array_merge($tables_to_remove, array_values(get_object_vars($table))); } foreach ($tables_to_remove as $table_name) { $wpdb->query('DROP TABLE '.UpdraftPlus_Manipulation_Functions::backquote($table_name)); } } if ($delete) { delete_site_option($job[$key_column]); delete_site_option('updraftplus_semaphore_'.$nonce); } } $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->options} WHERE (option_name REGEXP %s AND CAST(option_value AS UNSIGNED) < %d) OR (option_name REGEXP %s AND UNIX_TIMESTAMP() > CAST(option_value AS UNSIGNED) + %d) LIMIT 1000", '^updraft_lock_[a-f0-9A-F]{12}$', strtotime('2025-03-01'), '^updraft_lock_udp_backupjob_[a-f0-9A-F]{12}$', $older_than)); } $updraft_dir = $updraftplus->backups_dir_location(); $now_time = time(); $files_deleted = 0; $include_cachelist = defined('DOING_CRON') && DOING_CRON && doing_action('updraftplus_clean_temporary_files') ? true : $include_cachelist; if ($handle = opendir($updraft_dir)) { while (false !== ($entry = readdir($handle))) { $manifest_match = preg_match("/updraftplus-manifest\.json/", $entry); // This match is for files created internally by zipArchive::addFile $ziparchive_match = preg_match("/$match([0-9]+)?\.zip\.tmp\.(?:[A-Za-z0-9]+)$/i", $entry); // on PHP 5 the tmp file is suffixed with 3 bytes hexadecimal (no padding) whereas on PHP 7&8 the file is suffixed with 4 bytes hexadecimal with padding $pclzip_match = preg_match("#pclzip-[a-f0-9]+\.(?:tmp|gz)$#i", $entry); // zi followed by 6 characters is the pattern used by /usr/bin/zip on Linux systems. It's safe to check for, as we have nothing else that's going to match that pattern. $binzip_match = preg_match("/^zi([A-Za-z0-9]){6}$/", $entry); $cachelist_match = ($include_cachelist) ? preg_match("/-cachelist-.*(?:info|\.tmp)$/i", $entry) : false; $browserlog_match = preg_match('/^log\.[0-9a-f]+-browser\.txt$/', $entry); $downloader_client_match = preg_match("/$match([0-9]+)?\.zip\.tmp\.(?:[A-Za-z0-9]+)\.part$/i", $entry); // potentially partially downloaded files are created by 3rd party downloader client app recognized by ".part" extension at the end of the backup file name (e.g. .zip.tmp.3b9r8r.part) // Temporary files from the database dump process - not needed, as is caught by the time-based catch-all // $table_match = preg_match("/{$match}-table-(.*)\.table(\.tmp)?\.gz$/i", $entry); // The gz goes in with the txt, because we *don't* want to reap the raw .txt files if ((preg_match("/$match\.(tmp|table|txt\.gz)(\.gz)?$/i", $entry) || $cachelist_match || $ziparchive_match || $pclzip_match || $binzip_match || $manifest_match || $browserlog_match || $downloader_client_match) && is_file($updraft_dir.'/'.$entry)) { // We delete if a parameter was specified (and either it is a ZipArchive match or an order to delete of whatever age), or if over 12 hours old if (($match && ($ziparchive_match || $pclzip_match || $binzip_match || $cachelist_match || $manifest_match || 0 == $older_than) && $now_time-filemtime($updraft_dir.'/'.$entry) >= $older_than) || $now_time-filemtime($updraft_dir.'/'.$entry)>43200) { $skip_dblog = (0 == $files_deleted % 25) ? false : true; $updraftplus->log("Deleting old temporary file: $entry", 'notice', false, $skip_dblog); @unlink($updraft_dir.'/'.$entry);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise if the file doesn't exist. $files_deleted++; } } elseif (preg_match('/^log\.[0-9a-f]+\.txt$/', $entry) && $now_time-filemtime($updraft_dir.'/'.$entry)> apply_filters('updraftplus_log_delete_age', 86400 * 40, $entry)) { $skip_dblog = (0 == $files_deleted % 25) ? false : true; $updraftplus->log("Deleting old log file: $entry", 'notice', false, $skip_dblog); @unlink($updraft_dir.'/'.$entry);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise if the file doesn't exist. $files_deleted++; } } @closedir($handle);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function. } // Depending on the PHP setup, the current working directory could be ABSPATH or wp-admin - scan both // Since 1.9.32, we set them to go into $updraft_dir, so now we must check there too. Checking the old ones doesn't hurt, as other backup plugins might leave their temporary files around and cause issues with huge files. foreach (array(ABSPATH, ABSPATH.'wp-admin/', $updraft_dir.'/') as $path) { if ($handle = opendir($path)) { while (false !== ($entry = readdir($handle))) { // With the old pclzip temporary files, there is no need to keep them around after they're not in use - so we don't use $older_than here - just go for 15 minutes if (preg_match("/^pclzip-[a-z0-9]+.tmp$/", $entry) && $now_time-filemtime($path.$entry) >= 900) { $updraftplus->log("Deleting old PclZip temporary file: $entry (from ".basename($path).")"); @unlink($path.$entry);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise if the file doesn't exist. } } @closedir($handle);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function. } } } /** * Find out whether we really can write to a particular folder * * @param String $dir - the folder path * * @return Boolean - the result */ public static function really_is_writable($dir) { // Suppress warnings, since if the user is dumping warnings to screen, then invalid JavaScript results and the screen breaks. if (!@is_writable($dir)) return false;// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function. // Found a case - GoDaddy server, Windows, PHP 5.2.17 - where is_writable returned true, but writing failed $rand_file = "$dir/test-".md5(rand().time()).".txt"; while (file_exists($rand_file)) { $rand_file = "$dir/test-".md5(rand().time()).".txt"; } $ret = @file_put_contents($rand_file, 'testing...');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function. @unlink($rand_file);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise if the file doesn't exist. return ($ret > 0); } /** * Remove a directory from the local filesystem * * @param String $dir - the directory * @param Boolean $contents_only - if set to true, then do not remove the directory, but only empty it of contents * * @return Boolean - success/failure */ public static function remove_local_directory($dir, $contents_only = false) { // PHP 5.3+ only // foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST) as $path) { // $path->isFile() ? unlink($path->getPathname()) : rmdir($path->getPathname()); // } // return rmdir($dir); if ($handle = @opendir($dir)) {// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function. while (false !== ($entry = readdir($handle))) { if ('.' !== $entry && '..' !== $entry) { if (is_dir($dir.'/'.$entry)) { self::remove_local_directory($dir.'/'.$entry, false); } else { @unlink($dir.'/'.$entry);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise if the file doesn't exist. } } } @closedir($handle);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function. } return $contents_only ? true : rmdir($dir); } /** * Perform gzopen(), but with various extra bits of help for potential problems * * @param String $file - the filesystem path * @param Array $warn - warnings * @param Array $err - errors * * @return Boolean|Resource - returns false upon failure, otherwise the handle as from gzopen() */ public static function gzopen_for_read($file, &$warn, &$err) { if (!function_exists('gzopen') || !function_exists('gzread')) { $missing = ''; if (!function_exists('gzopen')) $missing .= 'gzopen'; if (!function_exists('gzread')) $missing .= ($missing) ? ', gzread' : 'gzread'; /* translators: %s: List of disabled PHP functions. */ $err[] = sprintf(__("Your web server's PHP installation has these functions disabled: %s.", 'updraftplus'), $missing).' '. sprintf( /* translators: %s: The process that requires the functions. */ __('Your hosting company must enable these functions before %s can work.', 'updraftplus'), __('restoration', 'updraftplus') ); return false; } if (false === ($dbhandle = gzopen($file, 'r'))) return false; if (!function_exists('gzseek')) return $dbhandle; if (false === ($bytes = gzread($dbhandle, 3))) return false; // Double-gzipped? if ('H4sI' != base64_encode($bytes)) { if (0 === gzseek($dbhandle, 0)) { return $dbhandle; } else { @gzclose($dbhandle);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function. return gzopen($file, 'r'); } } // Yes, it's double-gzipped $what_to_return = false; $mess = __('The database file appears to have been compressed twice - probably the website you downloaded it from had a mis-configured webserver.', 'updraftplus'); $messkey = 'doublecompress'; $err_msg = ''; if (false === ($fnew = fopen($file.".tmp", 'w')) || !is_resource($fnew)) { @gzclose($dbhandle);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function. $err_msg = __('The attempt to undo the double-compression failed.', 'updraftplus'); } else { @fwrite($fnew, $bytes);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function. $emptimes = 0; while (!gzeof($dbhandle)) { $bytes = @gzread($dbhandle, 262144);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function. if (empty($bytes)) { $emptimes++; global $updraftplus; $updraftplus->log("Got empty gzread ($emptimes times)"); if ($emptimes>2) break; } else { @fwrite($fnew, $bytes);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function. } } gzclose($dbhandle); fclose($fnew); // On some systems (all Windows?) you can't rename a gz file whilst it's gzopened if (!rename($file.".tmp", $file)) { $err_msg = __('The attempt to undo the double-compression failed.', 'updraftplus'); } else { $mess .= ' '.__('The attempt to undo the double-compression succeeded.', 'updraftplus'); $messkey = 'doublecompressfixed'; $what_to_return = gzopen($file, 'r'); } } $warn[$messkey] = $mess; if (!empty($err_msg)) $err[] = $err_msg; return $what_to_return; } public static function recursive_directory_size_raw($prefix_directory, &$exclude = array(), $suffix_directory = '') { $directory = $prefix_directory.('' == $suffix_directory ? '' : '/'.$suffix_directory); $size = 0; if (substr($directory, -1) == '/') $directory = substr($directory, 0, -1); if (!file_exists($directory) || !is_dir($directory) || !is_readable($directory)) return -1; if (file_exists($directory.'/.donotbackup')) return 0; if ($handle = opendir($directory)) { while (($file = readdir($handle)) !== false) { if ('.' != $file && '..' != $file) { $spath = ('' == $suffix_directory) ? $file : $suffix_directory.'/'.$file; if (false !== ($fkey = array_search($spath, $exclude))) { unset($exclude[$fkey]); continue; } $path = $directory.'/'.$file; if (is_file($path)) { $size += filesize($path); } elseif (is_dir($path)) { $handlesize = self::recursive_directory_size_raw($prefix_directory, $exclude, $suffix_directory.('' == $suffix_directory ? '' : '/').$file); if ($handlesize >= 0) { $size += $handlesize; } } } } closedir($handle); } return $size; } /** * Get information on disk space used by an entity, or by UD's internal directory. Returns as a human-readable string. * * @param String $entity - the entity (e.g. 'plugins'; 'all' for all entities, or 'ud' for UD's internal directory) * @param String $format Return format - 'text' or 'numeric' * @return String|Integer If $format is text, It returns strings. Otherwise integer value. */ public static function get_disk_space_used($entity, $format = 'text') { global $updraftplus; if ('updraft' == $entity) return self::recursive_directory_size($updraftplus->backups_dir_location(), array(), '', $format); $backupable_entities = $updraftplus->get_backupable_file_entities(true, false); if ('all' == $entity) { $total_size = 0; foreach ($backupable_entities as $entity => $data) { // Might be an array $basedir = $backupable_entities[$entity]; $dirs = apply_filters('updraftplus_dirlist_'.$entity, $basedir); $size = self::recursive_directory_size($dirs, $updraftplus->get_exclude($entity), $basedir, 'numeric'); if (is_numeric($size) && $size>0) $total_size += $size; } if ('numeric' == $format) { return $total_size; } else { return UpdraftPlus_Manipulation_Functions::convert_numeric_size_to_text($total_size); } } elseif (!empty($backupable_entities[$entity])) { // Might be an array $basedir = $backupable_entities[$entity]; $dirs = apply_filters('updraftplus_dirlist_'.$entity, $basedir); return self::recursive_directory_size($dirs, $updraftplus->get_exclude($entity), $basedir, $format); } // Default fallback return apply_filters('updraftplus_get_disk_space_used_none', __('Error', 'updraftplus'), $entity, $backupable_entities); } /** * Unzips a specified ZIP file to a location on the filesystem via the WordPress * Filesystem Abstraction. Forked from WordPress core in version 5.1-alpha-44182, * to allow us to provide feedback on progress. * * Assumes that WP_Filesystem() has already been called and set up. Does not extract * a root-level __MACOSX directory, if present. * * Attempts to increase the PHP memory limit before uncompressing. However, * the most memory required shouldn't be much larger than the archive itself. * * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass. * * @param String $file - Full path and filename of ZIP archive. * @param String $to - Full path on the filesystem to extract archive to. * @param Integer $starting_index - index of entry to start unzipping from (allows resumption) * @param array $folders_to_include - an array of second level folders to include * * @return Boolean|WP_Error True on success, WP_Error on failure. */ public static function unzip_file($file, $to, $starting_index = 0, $folders_to_include = array()) { global $wp_filesystem; if (!$wp_filesystem || !is_object($wp_filesystem)) { return new WP_Error('fs_unavailable', __('Could not access filesystem.'));// phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- The string exists within the WordPress core. } // Unzip can use a lot of memory, but not this much hopefully. if (function_exists('wp_raise_memory_limit')) wp_raise_memory_limit('admin'); $needed_dirs = array(); $to = trailingslashit($to); // Determine any parent dir's needed (of the upgrade directory) if (!$wp_filesystem->is_dir($to)) { // Only do parents if no children exist $path = preg_split('![/\\\]!', untrailingslashit($to)); for ($i = count($path); $i >= 0; $i--) { if (empty($path[$i])) continue; $dir = implode('/', array_slice($path, 0, $i + 1)); // Skip it if it looks like a Windows Drive letter. if (preg_match('!^[a-z]:$!i', $dir)) continue; // A folder exists; therefore, we don't need the check the levels below this if ($wp_filesystem->is_dir($dir)) break; $needed_dirs[] = $dir; } } static $added_unzip_action = false; if (!$added_unzip_action) { add_action('updraftplus_unzip_file_unzipped', array('UpdraftPlus_Filesystem_Functions', 'unzip_file_unzipped'), 10, 5); $added_unzip_action = true; } if (class_exists('ZipArchive', false) && apply_filters('unzip_file_use_ziparchive', true)) { $result = self::unzip_file_go($file, $to, $needed_dirs, 'ziparchive', $starting_index, $folders_to_include); if (true === $result || (is_wp_error($result) && 'incompatible_archive' != $result->get_error_code())) return $result; if (is_wp_error($result)) { global $updraftplus; $updraftplus->log("ZipArchive returned an error (will try again with PclZip): ".$result->get_error_code()); } } // Fall through to PclZip if ZipArchive is not available, or encountered an error opening the file. // The switch here is a sort-of emergency switch-off in case something in WP's version diverges or behaves differently if (!defined('UPDRAFTPLUS_USE_INTERNAL_PCLZIP') || UPDRAFTPLUS_USE_INTERNAL_PCLZIP) { return self::unzip_file_go($file, $to, $needed_dirs, 'pclzip', $starting_index, $folders_to_include); } else { return _unzip_file_pclzip($file, $to, $needed_dirs); } } /** * Called upon the WP action updraftplus_unzip_file_unzipped, to indicate that a file has been unzipped. * * @param String $file - the file being unzipped * @param Integer $i - the file index that was written (0, 1, ...) * @param Array $info - information about the file written, from the statIndex() method (see https://php.net/manual/en/ziparchive.statindex.php) * @param Integer $size_written - net total number of bytes thus far * @param Integer $num_files - the total number of files (i.e. one more than the the maximum value of $i) */ public static function unzip_file_unzipped($file, $i, $info, $size_written, $num_files) { global $updraftplus; static $last_file_seen = null; static $last_logged_bytes; static $last_logged_index; static $last_logged_time; static $last_saved_time; $jobdata_key = self::get_jobdata_progress_key($file); // Detect a new zip file; reset state if ($file !== $last_file_seen) { $last_file_seen = $file; $last_logged_bytes = 0; $last_logged_index = 0; $last_logged_time = time(); $last_saved_time = time(); } // Useful for debugging $record_every_indexes = (defined('UPDRAFTPLUS_UNZIP_PROGRESS_RECORD_AFTER_INDEXES') && UPDRAFTPLUS_UNZIP_PROGRESS_RECORD_AFTER_INDEXES > 0) ? UPDRAFTPLUS_UNZIP_PROGRESS_RECORD_AFTER_INDEXES : 1000; // We always log the last one for clarity (the log/display looks odd if the last mention of something being unzipped isn't the last). Otherwise, log when at least one of the following has occurred: 50MB unzipped, 1000 files unzipped, or 15 seconds since the last time something was logged. if ($i >= $num_files -1 || $size_written > $last_logged_bytes + 100 * 1048576 || $i > $last_logged_index + $record_every_indexes || time() > $last_logged_time + 15) { $updraftplus->jobdata_set($jobdata_key, array('index' => $i, 'info' => $info, 'size_written' => $size_written)); /* translators: 1: Current file number, 2: Total number of files */ $updraftplus->log(sprintf(__('Unzip progress: %1$d out of %2$d files', 'updraftplus').' (%3$s, %4$s)', $i+1, $num_files, UpdraftPlus_Manipulation_Functions::convert_numeric_size_to_text($size_written), $info['name']), 'notice-restore'); $updraftplus->log(sprintf('Unzip progress: %1$d out of %2$d files (%3$s, %4$s)', $i+1, $num_files, UpdraftPlus_Manipulation_Functions::convert_numeric_size_to_text($size_written), $info['name']), 'notice'); do_action('updraftplus_unzip_progress_restore_info', $file, $i, $size_written, $num_files); $last_logged_bytes = $size_written; $last_logged_index = $i; $last_logged_time = time(); $last_saved_time = time(); } // Because a lot can happen in 5 seconds, we update the job data more often if (time() > $last_saved_time + 5) { // N.B. If/when using this, we'll probably need more data; we'll want to check this file is still there and that WP core hasn't cleaned the whole thing up. $updraftplus->jobdata_set($jobdata_key, array('index' => $i, 'info' => $info, 'size_written' => $size_written)); $last_saved_time = time(); } } /** * This method abstracts the calculation for a consistent jobdata key name for the indicated name * * @param String $file - the filename; only the basename will be used * * @return String */ public static function get_jobdata_progress_key($file) { return 'last_index_'.md5(basename($file)); } /** * Compatibility function (exists in WP 4.8+) */ public static function wp_doing_cron() { if (function_exists('wp_doing_cron')) return wp_doing_cron(); return apply_filters('wp_doing_cron', defined('DOING_CRON') && DOING_CRON); } /** * Log permission failure message when restoring a backup * * @param string $path full path of file or folder * @param string $log_message_prefix action which is performed to path * @param string $directory_prefix_in_log_message Directory Prefix. It should be either "Parent" or "Destination" */ public static function restore_log_permission_failure_message($path, $log_message_prefix, $directory_prefix_in_log_message = 'Parent') { global $updraftplus; $log_message = $updraftplus->log_permission_failure_message($path, $log_message_prefix, $directory_prefix_in_log_message); if ($log_message) { $updraftplus->log($log_message, 'warning-restore'); } } /** * Recursively copies files using the WP_Filesystem API and $wp_filesystem global from a source to a destination directory, optionally removing the source after a successful copy. * * @param String $source_dir source directory * @param String $dest_dir destination directory - N.B. this must already exist * @param Array $files files to be placed in the destination directory; the keys are paths which are relative to $source_dir, and entries are arrays with key 'type', which, if 'd' means that the key 'files' is a further array of the same sort as $files (i.e. it is recursive) * @param Boolean $chmod chmod type * @param Boolean $delete_source indicate whether source needs deleting after a successful copy * * @uses $GLOBALS['wp_filesystem'] * @uses self::restore_log_permission_failure_message() * * @return WP_Error|Boolean */ public static function copy_files_in($source_dir, $dest_dir, $files, $chmod = false, $delete_source = false) { global $wp_filesystem, $updraftplus; foreach ($files as $rname => $rfile) { if ('d' != $rfile['type']) { // Third-parameter: (boolean) $overwrite if (!$wp_filesystem->move($source_dir.'/'.$rname, $dest_dir.'/'.$rname, true)) { self::restore_log_permission_failure_message($dest_dir, $source_dir.'/'.$rname.' -> '.$dest_dir.'/'.$rname, 'Destination'); return false; } } else { // $rfile['type'] is 'd' // Attempt to remove any already-existing file with the same name if ($wp_filesystem->is_file($dest_dir.'/'.$rname)) @$wp_filesystem->delete($dest_dir.'/'.$rname, false, 'f');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- if fails, carry on // No such directory yet: just move it if ($wp_filesystem->exists($dest_dir.'/'.$rname) && !$wp_filesystem->is_dir($dest_dir.'/'.$rname) && !$wp_filesystem->move($source_dir.'/'.$rname, $dest_dir.'/'.$rname, false)) { self::restore_log_permission_failure_message($dest_dir, 'Move '.$source_dir.'/'.$rname.' -> '.$dest_dir.'/'.$rname, 'Destination'); $updraftplus->log_e('Failed to move directory (check your file permissions and disk quota): %s', $source_dir.'/'.$rname." -> ".$dest_dir.'/'.$rname); return false; } elseif (!empty($rfile['files'])) { if (!$wp_filesystem->exists($dest_dir.'/'.$rname)) $wp_filesystem->mkdir($dest_dir.'/'.$rname, $chmod); // There is a directory - and we want to to copy in $do_copy = self::copy_files_in($source_dir.'/'.$rname, $dest_dir.'/'.$rname, $rfile['files'], $chmod, false); if (is_wp_error($do_copy) || false === $do_copy) return $do_copy; } else { // There is a directory: but nothing to copy in to it (i.e. $file['files'] is empty). Just remove the directory. @$wp_filesystem->rmdir($source_dir.'/'.$rname);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the method. } } } // We are meant to leave the working directory empty. Hence, need to rmdir() once a directory is empty. But not the root of it all in case of others/wpcore. if ($delete_source || false !== strpos($source_dir, '/')) { if (!$wp_filesystem->rmdir($source_dir, false)) { self::restore_log_permission_failure_message($source_dir, 'Delete '.$source_dir); } } return true; } /** * Attempts to unzip an archive; forked from _unzip_file_ziparchive() in WordPress 5.1-alpha-44182, and modified to use the UD zip classes. * * Assumes that WP_Filesystem() has already been called and set up. * * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass. * * @param String $file - full path and filename of ZIP archive. * @param String $to - full path on the filesystem to extract archive to. * @param Array $needed_dirs - a partial list of required folders needed to be created. * @param String $method - either 'ziparchive' or 'pclzip'. * @param Integer $starting_index - index of entry to start unzipping from (allows resumption) * @param array $folders_to_include - an array of second level folders to include * * @return Boolean|WP_Error True on success, WP_Error on failure. */ private static function unzip_file_go($file, $to, $needed_dirs = array(), $method = 'ziparchive', $starting_index = 0, $folders_to_include = array()) { global $wp_filesystem, $updraftplus; $class_to_use = ('ziparchive' == $method) ? 'UpdraftPlus_ZipArchive' : 'UpdraftPlus_PclZip'; if (!class_exists($class_to_use)) updraft_try_include_file('includes/class-zip.php', 'require_once'); $updraftplus->log('Unzipping '.basename($file).' to '.$to.' using '.$class_to_use.', starting index '.$starting_index); $z = new $class_to_use; $flags = (version_compare(PHP_VERSION, '5.2.12', '>') && defined('ZIPARCHIVE::CHECKCONS')) ? ZIPARCHIVE::CHECKCONS : 4; // This is just for crazy people with mbstring.func_overload enabled (deprecated from PHP 7.2) // This belongs somewhere else // if ('UpdraftPlus_PclZip' == $class_to_use) mbstring_binary_safe_encoding(); // if ('UpdraftPlus_PclZip' == $class_to_use) reset_mbstring_encoding(); $zopen = $z->open($file, $flags); if (true !== $zopen) { return new WP_Error('incompatible_archive', __('Incompatible Archive.'), array($method.'_error' => $z->last_error));// phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- The string exists within the WordPress core. } $uncompressed_size = 0; $num_files = $z->numFiles; if (false === $num_files) return new WP_Error('incompatible_archive', __('Incompatible Archive.'), array($method.'_error' => $z->last_error));// phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- The string exists within the WordPress core. for ($i = $starting_index; $i < $num_files; $i++) { if (!$info = $z->statIndex($i)) { return new WP_Error('stat_failed_'.$method, __('Could not retrieve file from archive.').' ('.$z->last_error.')');// phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- The string exists within the WordPress core. } // Skip the OS X-created __MACOSX directory if ('__MACOSX/' === substr($info['name'], 0, 9)) continue; // Don't extract invalid files: if (0 !== validate_file($info['name'])) continue; if (!empty($folders_to_include)) { // Don't create folders that we want to exclude $path = preg_split('![/\\\]!', untrailingslashit($info['name'])); if (isset($path[1]) && !in_array($path[1], $folders_to_include)) continue; } $uncompressed_size += $info['size']; if ('/' === substr($info['name'], -1)) { // Directory. $needed_dirs[] = $to . untrailingslashit($info['name']); } elseif ('.' !== ($dirname = dirname($info['name']))) { // Path to a file. $needed_dirs[] = $to . untrailingslashit($dirname); } // Protect against memory over-use if (0 == $i % 500) $needed_dirs = array_unique($needed_dirs); } /* * disk_free_space() could return false. Assume that any falsey value is an error. * A disk that has zero free bytes has bigger problems. * Require we have enough space to unzip the file and copy its contents, with a 10% buffer. */ if (self::wp_doing_cron()) { $available_space = function_exists('disk_free_space') ? @disk_free_space(WP_CONTENT_DIR) : false;// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Call is speculative if ($available_space && ($uncompressed_size * 2.1) > $available_space) { return new WP_Error('disk_full_unzip_file', __('Could not copy files.').' '.__('You may have run out of disk space.'), compact('uncompressed_size', 'available_space'));// phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- The string exists within the WordPress core. } } $needed_dirs = array_unique($needed_dirs); foreach ($needed_dirs as $dir) { // Check the parent folders of the folders all exist within the creation array. if (untrailingslashit($to) == $dir) { // Skip over the working directory, We know this exists (or will exist) continue; } // If the directory is not within the working directory then skip it if (false === strpos($dir, $to)) continue; $parent_folder = dirname($dir); while (!empty($parent_folder) && untrailingslashit($to) != $parent_folder && !in_array($parent_folder, $needed_dirs)) { $needed_dirs[] = $parent_folder; $parent_folder = dirname($parent_folder); } } asort($needed_dirs); // Create those directories if need be: foreach ($needed_dirs as $_dir) { // Only check to see if the Dir exists upon creation failure. Less I/O this way. if (!$wp_filesystem->mkdir($_dir, FS_CHMOD_DIR) && !$wp_filesystem->is_dir($_dir)) { return new WP_Error('mkdir_failed_'.$method, __('Could not create directory.'), substr($_dir, strlen($to)));// phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- The string exists within the WordPress core. } } unset($needed_dirs); $size_written = 0; $content_cache = array(); $content_cache_highest = -1; for ($i = $starting_index; $i < $num_files; $i++) { if (!$info = $z->statIndex($i)) { return new WP_Error('stat_failed_'.$method, __('Could not retrieve file from archive.'));// phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- The string exists within the WordPress core. } // directory if ('/' == substr($info['name'], -1)) continue; // Don't extract the OS X-created __MACOSX if ('__MACOSX/' === substr($info['name'], 0, 9)) continue; // Don't extract invalid files: if (0 !== validate_file($info['name'])) continue; if (!empty($folders_to_include)) { // Don't extract folders that we want to exclude $path = preg_split('![/\\\]!', untrailingslashit($info['name'])); if (isset($path[1]) && !in_array($path[1], $folders_to_include)) continue; } // N.B. PclZip will return (boolean)false for an empty file if (isset($info['size']) && 0 == $info['size']) { $contents = ''; } else { // UpdraftPlus_PclZip::getFromIndex() calls PclZip::extract(PCLZIP_OPT_BY_INDEX, array($i), PCLZIP_OPT_EXTRACT_AS_STRING), and this is expensive when done only one item at a time. We try to cache in chunks for good performance as well as being able to resume. if ($i > $content_cache_highest && 'UpdraftPlus_PclZip' == $class_to_use) { $memory_usage = memory_get_usage(false); $total_memory = $updraftplus->memory_check_current(); if ($memory_usage > 0 && $total_memory > 0) { $memory_free = $total_memory*1048576 - $memory_usage; } else { // A sane default. Anything is ultimately better than WP's default of just unzipping everything into memory. $memory_free = 50*1048576; } $use_memory = max(10485760, $memory_free - 10485760); $total_byte_count = 0; $content_cache = array(); $cache_indexes = array(); $cache_index = $i; while ($cache_index < $num_files && $total_byte_count < $use_memory) { if (false !== ($cinfo = $z->statIndex($cache_index)) && isset($cinfo['size']) && '/' != substr($cinfo['name'], -1) && '__MACOSX/' !== substr($cinfo['name'], 0, 9) && 0 === validate_file($cinfo['name'])) { $total_byte_count += $cinfo['size']; if ($total_byte_count < $use_memory) { $cache_indexes[] = $cache_index; $content_cache_highest = $cache_index; } } $cache_index++; } if (!empty($cache_indexes)) { $content_cache = $z->updraftplus_getFromIndexBulk($cache_indexes); } } $contents = isset($content_cache[$i]) ? $content_cache[$i] : $z->getFromIndex($i); } if (false === $contents && ('pclzip' !== $method || 0 !== $info['size'])) { return new WP_Error('extract_failed_'.$method, __('Could not extract file from archive.').' '.$z->last_error, json_encode($info));// phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- The string exists within the WordPress core. } if (!$wp_filesystem->put_contents($to . $info['name'], $contents, FS_CHMOD_FILE)) { return new WP_Error('copy_failed_'.$method, __('Could not copy file.'), $info['name']);// phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- The string exists within the WordPress core. } if (!empty($info['size'])) $size_written += $info['size']; do_action('updraftplus_unzip_file_unzipped', $file, $i, $info, $size_written, $num_files); } $z->close(); return true; } } David Richards, Author at Smart Office - Page 56 of 91

    Smart Office

    Senior OZ Executives & Government Officals Targeted By Hackers

    Australian Government officals and senior business executives are being targeted by hackers with security experts claiming that the attacks could be the work of foreign Governments.

    The scam, known as spear phishing, was used in a bid to get passwords of Gmail accounts so they could be monitored. The targeted attack was also used by hackers to compromise e-mail accounts of top US officials.

    Dan Kaminsky, chief scientist at security firm DKH, said:”What is happening more and more is the targeting of a couple of high value individuals with the one goal of acquiring valuable information and valuable data,” said

    He told the BBC that via a small number of customised messages it tries to trick people into visiting a web page that looks genuine so users type in login names.

    Such attacks are often aimed at top government officials or chief executives of top 100 Companies.

    Such attacks are not new, he claims, but they are becoming more commonplace.

    “The most interesting information is concentrated in the accounts of a few people,” he said. “Attackers using information to impersonate the users is at epidemic proportions and why computer security is in the state it is in.”

    In March, security firm RSA was hit by a sophisticated spear-phishing attack that succeeded despite only two attacking e-mails being sent. The phishing e-mail had the subject line “2011 Recruitment Plan” and contained a booby-trapped spreadsheet.

    Total access
    Google said it uncovered the deception through a combination of cloud based security measures, abuse detections systems and user reports. It also cited work done by a website called contagio dump.

    The founder of the site is technologist and researcher Mila Parkour who said the method used in this attack was “far from being new or sophisticated”.

    The RSA attack involved two e-mails sent to a small group of high-value individuals.

    She told the BBC she was first alerted to the problem by one individual back in February. She would not reveal their name or position.

    Google said that among those targeted were senior government officials, military personnel, journalists, Chinese political activists and officials in several Asia Pacific countries.

    Clive Peeters Bleeds In NSW

    Clive Peeters is set to report their half year results on the 27th February 2009 however analysts are tipping a net loss of $0.4M which represents a decline of 104%. Sales are believed to be down 16.3%.

    Contributing to the losses is a major downturn in NSW with analysts tipping losses in this State to be between $1M and $3M.

    One analyst writes in a briefing to vendors “We expect performance from NSW to be disappointing, with the tough trading environment, the large upfront marketing costs and the lack of brand traction to be the main contributor of the A$1.7m EBIT loss. We have assumed no interim dividend”.

    They added “Losses in NSW – We expect losses in FY09 and FY10 of A$3m and A$1m, respectively. An update on conversion rates and a discussion of potential changes to store locations (closure of some poorly located stores, opening better located stores) is expected. A weak trading environment and store openings may put further constraints on cash flow.

    Several vendors that ChannelNews has spoken to claim that they are waiting for the KPMG report into the operations of Clive Peeters.

    LCD Screen Glut Coming

    Major LCD manufacturers like LG.Philips, Samsung Electronics and a host of Taiwanese manufacturers may face a greater-than-expected glut of screens in the second half, according to US market researcher iSuppli.

     Third-quarter supply of LCDs measuring at least 10in diagonally will exceed demand by 5 per cent, compared with an earlier forecast of a 3.8 per cent glut, according to a statement issued by iSuppli. Consumers are not buying as many large-screen LCD televisions as expected and there is an inventory build-up of panels used in computer monitors, it says.

    iSuppli joins other analysts, including those at Macquarie Securities and CJ Investment and Securities, in saying producers in the $US35 billion ($46 billion) industry may have overestimated demand as higher oil prices threaten to keep consumers from buying televisions and computers.

    The International Monetary Fund has cut its estimate for global economic growth and says risks are currently “slanted to the downside”. “There’s definitely an oversupply and intense competition,” says Nicholas Yeo, an investment manager at Singapore’s Aberdeen Asset Management, which manages $US12 billion including Samsung shares.

    “LCD makers are seeing one of the shortest recoveries in the industry.” Higher oil prices, lower consumer confidence and slower economic growth may prevent second-half LCD sales from meeting earlier expectations, according to the research company.

    Macquarie analyst Michael Bang has cut his stock recommendations on LCD makers including South Korea’s LG.Philips LCD and Hsinchu and Taiwan’s AU Optronics, the industry’s third-largest producer. Macquarie recommends investors switch to memory chip-makers such as Hynix Semiconductor, according to the market-research report.

    Seoul’s CJ Investment cut its target price on LG.Philips LCD’s stock earlier this month, citing concern that panel prices may fall as demand growth slows. iSuppli also raised its oversupply projection for the fourth quarter to 6.2 per cent from an earlier 4.2 per cent estimate.

    Shares of the world’s top-six LCD makers, all based in Asia, fell. Not all analysts agree with iSuppli and Macquarie’s view. “Inventory levels remain stable and LCD TV demand could emerge sooner than expected,” Citigroup’s Taipei-based analyst George Chang says in a report issued last week.

    “We expect their shipments to continue to grow, driven by seasonal strength in the near term.”

    Chang maintained his “buy” rating on panel makers. Samsung, Asia’s largest electronics maker by market value, has become more optimistic on the LCD business.
    The company raised its shipment forecasts for the industry by 6.7 per cent, citing higher-than-expected demand for panels used in televisions and computers, Samsung’s head of investor relations Chu Woo Sik says. Samsung expects global shipments of LCD panels measuring at least 10 inches diagonally to rise 46 per cent to 191 million units this year from 131 million last year, Chu says.  Shipments for 2006 are expected to increase 24 per cent to 236 million units, he says.

    E3 Style Up For Sale As Legal Fights Eats Into Profits

    E3 the Brisbane based distributor who is embroiled in several legal cases is up for sale.

    According to ChannelNews sources, several potential owners have been approached to invest in the business despite current management being reluctant to let third party accountants audit the books.

    E3 Style, is part owned by Vannessa Garrard and her husband, while part of the business is owned by a third party via a blind trust. 

    Currently the Company that use to be a major supplier to Dick Smith and JB Hi Fi two retailers who no longer deal with e3 Style, is fighting legal cases on several fronts. 

    In the Supreme Court a multimillion dollar claim has been lodged against The Crest Company which is another Sydney based distributor where Garrard worked as a PA and later as an account manager. 

    Garrard is also facing legal action over a disputed $285,000 investment by South Australian distributor Powermove involving a shipment of goods to a mass retailer.

    E3, who has been forced to lodge substantial security with the Courts is believed to be facing a cash crunch after a major retailer stopped using the Company to supply house brand products.

    The CEO of the mass retailer told ChannelNews that E3 was “not their favourite supplier, at the moment”.

    The CEO of one organisation approached to invest in E3 said “when you have lost key retailers it becomes difficult to place a value on an organisation like E3. There are a lot of Companies in Australia who can source house brand products, the value is in retailer relationships and access to licensed products”. 

    Garrard has also discussed merging E3 with other major distributors. 

    The Crest Vs E3 Style case due to be heard this year, has it all, allegations of treachery, stolen Officeworks ideas, claims of breach of confidentiality as well as allegations that Harvey Norman was looking to buy into a house brand sourcing Company.

    Vannessa Garrard has not only taken legal action against arch rival Crest, it’s employees and principle director, she also claims that a former employee Michael Tomkins took confidential information relating to deals that E3 were doing with Officeworks when he quit to join Crest.

    Last year E3 Style who ChannelNews believes has been struggling to fund shipments without major deposits similar to the one that Powermove put up last year, sold 50% of her business to a major consumer electronics distributor who E3 CEO Vannessa Garrard now claims are trying to mount a “hostile takeover.

    Crawford Giles the CEO of Powermove said that at this stage he did not want to discuss the case as matters were before the Courts in Queensland. 

    Currently Garrard is claiming the E3 Style is the largest youth electronics supplier in Australia, with 1 in 2 people owning an E3 developed product.
    They also claim that they are largest licensed electronics supplier in Australia and New Zealand. 
    E3 Style sells more cameras each year in Australia than any of the big global brands and has offices in Brisbane, China and Los Angeles to service clients around the globe.
    Several distributors have questioned these claims along with the validity of awards that line the walls of E3 offices. 

    Dell Moves To AMD

    Dell has contracted three Taiwanese manufacturers to supply it with PCs based on AMD processors, the Asian press has claimed.

    According to Chinese Language newspaper Economic Daily News this past weekend, Asus, Quanta and Hon Hai Precision (aka Foxconn) are all developing AMD-based systems for Dell. Their specialisms suggest the PC giant is buying desktops, notebooks and servers, respectively.Dell has traditionally been an Intel-only house, and is the only major Wintel systems vendor to hold out against AMD. Some observers claim Intel makes it worth Dell’s while, but Dell is canny enough to play the two chip makers off against each other to ensure it always gets the most favourable terms.

    Every so often, Dell drops hints it might launch AMD-based systems, much to the joy of AMD fanboys, but somehow never quite manages to do so. This month it began selling boxed AMD processors, seen by some as a change of heart – or a bulwark against any fall-out from AMD’s legal challenge to Intel. AMD accuses its arch-rival of deliberately attempting to harm its business, a charge Intel refutes.

    And of course Intel now has a second exclusive customer: Apple. The Mac maker’s decision to turn to Intel for its x86 chips could be seen to weaken Dell’s bargaining position, though in reality the scale of its processor purchasing activity dwarfs Apple’s.

    COMMENT: Why LG Needs To Sack Their CEO + Appoint A Local

    LG Australia, to coin a phrase is in deep shit, and it is not the first time that the Korean Company has found itself defending their shocking marketing practises in the Australian Federal Court.

    Now some observers are asking whether LG needs to urgently appointed an Australian CEO, who understands Australian consumer laws and can reassure their staff that they are actually working for a credible Company.

    Right now the Company that is run by Korean management who it appears are quite happy to flaunt Australian consumer laws despite being fined millions in the past. 

    People who have quit this Company during the past 12 months and that includes the head of marketing, the head of sales and personnel from various LG divisions claim the Company is a mess, with head hunters desperate to find senior management that actually want to work for LG Australia. 

    Senior management don’t want to work in what has been described as a hostile environment, actions taken by Korean management relating to ACCC undertakings appear to have been ignored despite LG putting in place a legal vetting process that has quite clearly failed.  

     Recently, when the Australian Competition and Consumer Commission, the Federal Government body empowered to protect consumers from dodgy manufacturers, came knocking on LG Australia’s door recently they knew exactly where to go.

    For the simple reason that over the past 10 years they have taken action against this Korean Company on numerous occasions for questionable consumer marketing practises resulting in the Korean Company being fined millions by the Federal watchdog. 

    Now it’s warranties relating to LG TV’s including their brand spanking new OLED TV’s that have caught the attention of ACCC investigators. 

    This time round the ACCC allege that LG misrepresented to consumers with defective televisions that any remedies available were only limited to the LG manufacturer’s warranty.

    If the LG warranty had expired, consumers were told they would have to pay the costs of assessing the failure, that the company had no further obligations, and any further step taken in relation to the television was an act of goodwill.

    They were also told they were only entitled to have the television repaired, and not be entitled to a refund or replacement, and that the consumer was liable for the labour costs of the repair.

    LG’s home entertainment marketing manager Grant Vandenberg is not commenting despite home entertainment being one of LG’s main categories.

    This is not the first time that LG has fallen foul of the ACCC.

    Between May 2004 and August 2004, LG Australia sold washing machines claiming that they were approved “4A Rated” by Water Services Association of Australia (WSAA) when in fact, at the time they were not.

    LG also released a brochure in June 2004 which represented that the machines were 4A certified and posted information to this effect on the LG Australia website.

    Western Australian consumers who bought these machines and approached the Water Corporation for a $150 Waterwise Rebate had their claims rejected, as certification was not complete until 28 August 2004.

    The ACCC at the time came to the conclusion that LG’s conduct in making these representations contravenes sections 52 and 53(c) of the Act.

    Back in 2010 LG Electronics agreed to compensate thousands of consumers after two of its fridges – models L197NFS and P197WFS – were found to contain an illegal device that activates an energy-saving mode when it detects room conditions similar to those in a test laboratory.

    The so-called circumvention device was discovered by consumer advocacy group Choice.

    The device similar to what Volkswagen used in their cars to deceive consumers detected test conditions and activated a mode, creating the impression of lower running costs and energy usage. 
    The devices have been banned in Australia since 2007.

    In reality the fridge, which had a 3.5-star energy rating, costs an extra $250 to run over 10 years, it also severely affects food quality because it could shut off when the fridge was opened.

    The electronics giant at the time agreed to “conduct additional testing on a selection of refrigerators, televisions, clothes washers, clothes dryers and dishwashers prior to release into the Australian market.”

    In 2006 LG agreed to provide consumers with up to $3.1 million in compensation after mislabelling 15,000 air conditioners which did not meet promised energy efficiency levels.

    Also in 2006, the Federal Court declared LG had made false and misleading statements about the existence and duration of statutory conditions and warranties.

    This real issue at LG is a management issue.

    Back in 2010 LG parachuted in William Cho, the former President and CEO of LG Canada, as the new Chief Executive of LG Australia, his job was to clean up yet another LG scandal.

    He replaces Daniel Shin who is now working in global sales as a marketing executive. 

    Cho, immediately initiated change. Senior management were sacked and new processes were put into place. 

    Five years on and under the management of LG Australia, Managing Director, Mr. Youngik Lee LG Australia has again come to the attention of the ACCC.

    Philip Anderson LG Australia’s PR Manager who has a reputation for putting out LG press releases only after they have been vetted by local in-house lawyers is today not returning calls.

    The irony is that it appears that press releases are okay to be vetted by in-house lawyers but not warranty claims affecting tens of thousands of Australians consumers. 

    A former LG manager said “I would love to read the exit interviews of at least 50 senior management” who have quit LG over the past decade,, I doubt whether there is any praise for current or past management”.

    They added “For this to happen again especially inside a Company the size of LG is unforgivable”.

    “something has gone very wrong and heads need to roll starting right at the top”.

    It is the opinion of ChannelNews that both Samsung and LG need local Australian management. People who understand how Australians think, buy and live.

    This is not Korean and like Australian management would not fit in running a Korean Company, Korean management do not have the skills necessary to run organisations that sell consumer products that are a key part of almost every Australians life. 
    They don’t have respect for Australian lifestyle or our business practises. What they want is the Korean way to be adhered to here in Australia and that means that everyone has to be workaholic. 

    Panasonic bit the bullet six years ago with the appointment of Steve Rust as CEO now Paul Reid the former head of consumer AV products at Panasonic is running the Company after a CEO stint in Europe. 

    If LG whose products are excellent is to get back any credibility, they need to appoint a local CEO who is empowered to make key decisions.
     
    His first task is to win over current employees, restructure the marketing and sales of the Company and above all become a key evangelist for LG.

    Currently LG Australia’s PR is hopeless, they churn our motherhood press releases that are often days if not weeks old.

    They fail to talk about the brand or innovation. Their idea of PR is like going back to the dark ages for the simple reason they employ “yes” people who bow down to their Korean masters rather than stand up for what actually works in Australia. 

    When was the last time anyone saw a major brand campaign from LG similar to what Samsung delivers to the market?

    It was back in 1999 to 2000, when Paul Reeves, the then marketing director at LG Australia had to go in boots and all to get dollars to spend on marketing.
     
    What he delivered included washing machines on pedestals and cut through consumer entertainment marketing that went on to establish LG as the ‘Life Is Good” brand in Australia.

    At a retail level LG started to get traction because they invested in brand marketing, at a consumer level the advertising Reeves dished up cut through and got attention. 

    In the end Reeves like a lot of other LG marketing directors after him, simply quit LG for new pastures, today he is COO at Betta Electrical.

    LG TV marketing today is nothing but Korean generated content, just take a look at those bloody awful pair of panther eyes staring at you from an OLED TV?

    Is that really going to convince you that LG is a serious brand when it comes to cutting edge technology. 

    At least Samsung has their curved screen gladiator which up against the LG panther sees my money on the gladiator.

    What LG is dishing up is penny pinching marketing that no Australian is going to take seriously. 
     
    Now is the time for both LG and Samsung to bite the bullet and appoint local management, the results could be seriously impressive. 

    I could name the two most suitable candidates for both organisations, they have both worked together and the competition between the two would not only grow sales, and result in great marketing but it would deliver respected individual at the top of each Company that both the industry and the staff of each Company would respect.

    B&O Appoints New CEO As Company Sinks Into A Hole

    Financially strapped Hi Fi Company Bang & Olufsen, who has not made a full year profit for three years, has appointed a new CEO, the move comes days after the opening of a new flagship store in Melbourne.

    Former Danish telecom executive Henrik Clausen will replace Tue Mantoni, who has been CEO since March 2011.

    The Danish Company whose direct sell shops are run in Australia by Emerald Group Investments, has been under siege as consumers move to new wireless sound systems instead of the high priced B&O sound systems. 
    They are also struggling in the TV market as Companies like Samsung and LG with their OLED TV technology deliver a new generation of premium TV’s.

    Back in 2012 the Company tried to come down market with their portable B&O Play system, at the time Company executives told ChannelNews that they were confident that mass retailers such as JB Hi Fi and Harvey Norman would range the portable product and that they were confident that the B&O Play range would take on products from Bose and Sonos.

    This did not happen with JB Hi Fi choosing to cut an exclusive deal with Bose to range their products over the Bang & Olufsen range.   

    The problem for B&O is that the European Company that has shops in most States of Australia hasn’t posted a full-year profit for the past three years. In recent months, the luxury audio/video company sold off its automotive audio unit to Harman, which also secured the right to use the B&O name on OEM sound systems. 

    B&O also recently announced plans to begin sourcing OLED TVs from LG to achieve scale and improve long-term profitability.

    The company also divested its ICEpower OEM audio-amplifier business.

    During the first nine months of its current fiscal year, B&O posted a net loss of $20 million, down from the year-ago loss of $33.2 million, despite a sales gain of 16.6 percent to$394.9 million. 

    North American revenue fell in the third quarter by 5.6 percent, this is a market that B&O has been dependant on to deliver sales growth.

    The leadership change follows a recent announcement that B&O terminated discussions with Sparkle Roll to take over the publicly held company.

    Sparkle Roll is led by the head of B&O’s distributor in Asia. 

    B&O said it called off the talks because, despite Sparke Roll’s interest, “Sparkle Roll has not committed to launch a tender offer for all shares in Bang & Olufsen and has not been able to substantiate its ability to launch such a tender offer.”

    Analysts claim that the Danish company, who is trying to push into the custom installation market in Australia selling proprietary B&O products is struggling because their core market of consumers is “dying off”. 
     
    The manufacturer has struggled to win buyers for its consumer products as prices for flat-screen televisions tumble and more people listen to music on the go on their smartphones or via a networked device at home.

     Morten Imsgard, an analyst at Sydbank A/S said “B&O shareholders should be more worried after this quarter than they were in the previous one.”

    The company, founded 90 years ago, is also struggling to roll out new products like the BeoSound Moment digital music hub due to innovation by Companies such as Samsung who is now delivering top end TV’s and cutting edge sound bars that incorporate technology such as Dolby Atmos.

    The company last paid a dividend for 2008.

    EXCLUSIVE: Harvey Norman To Distribute Monster + Solo 3DR Drone

    Ariston a Company that is 60% owned by Harvey Norman in Australia, is set to distribute the Monster brand along with the Solo 3DR drone.

    Sources at Harvey Norman have confirmed the move.

    Geoff Mathews the CEO of Convoy who currently distributes both Monster products and the Solo 3DR Drone has also confirmed that both brands will go to Ariston who market themselves as a distributor of Ariston appliances spanning ovens, laundry and cooktops.

     It’s not known what impact this will have on sales of the 3DR drone or Monster electrical products which are sold by several competing retailers.

    Currently the Solo 3DR is being sold by specialist dealers

    in Australia, it was also set to be sold via other mass retailers stores.


    Click to enlarge

    Meanwhile he Monster brand has seen sales slump in Australia, last

    year JB Hi Fi dropped the Monster headphone brand while sales of the Companies

    electrical and cable products are believed to have halved during the past 18

    months.

     
    When asked whether Harvey Norman were expanding into their distribution business via Ariston Mathews said “Ariston are taking Monster and 3DR and yes they are predominantly owned by Harvey Norman. The documentation is just drying now.
    When asked Is this Gerry Harvey moving into mass distribution, Mathews said “It could be, I know that Ariston is by majority owned by Harvey Norman”.

    Also going to Ariston is Adam Mills the former product manager for Solo 3DR.

    According to Mathews, the deal was finalised last week with paperwork drawn up today. 


    Last week ChannelNews broke the story that Convoy was getting out of the Consumer market to concentrate on the specialist Hi Fi market. 

    An Ariston employee told ChannelNews that the Company was “predominantly owned by Harvey Norman”.

    Simon Taylor the Managing Director of Ariston; was not available to comment.

    The Ariston web site claims that their products are designed and built by one of Europe’s largest home appliances company and that Ariston is Italy’s number 1 brand.

    What’s not known is whether the Monster products and the Solo 3DR Drone will be exclusively sold by Harvey Norman stores.

    Currently the Ariston appliance products are only sold by Harvey Norman. 

    EXCLUSIVE:Fighting Breaks Out Between Management At Dick Smith As Sales Slump

    Fighting has broken out between management at Dick Smith after store staff accused the Companies online team of “cannibalising store sales.

    Senior management from the struggling retailer were told during an internal conference call that store traffic at the struggling retailer was down, store management responded by blaming the impact of the Companies online operation. 

    Dick Smith CEO Nick Aboud told managers that “customer traffic is no excuse for stores not performing in sales”.

    ChannelNews understands that as of 25th of October internal sales budgets were down over $100 Million, while internal profit targets were down $26M.

    Aboud who has been personally driving the online sales operation, told managers that their claims were “smoke and mirrors” he “blamed the teams in stores for letting the company down” a comment that did not go down well with senior store managers who are struggling to grow their business. 

    According to sources Dick Smith wants online to make up 15% of their overall sales operation going forward. This claim management will take the pressure off the Companies looming cash flow crisis with distributors set to be used to fulfil orders for Dick Smith’s online operation.

    Both buyers and merchandising executives at Dick Smith, have told ChannelNews that there are real concerns over the Companies house brand strategies with senior executives claiming that a lack of “experience” in the Companies Hong Kong based house brand sourcing office, had led to major problems for buyers who they claim were not consulted about stock being shipped into stores.

    The General Manager of the Hong Kong Office for International Sourcing at Dick Smith Electronics is Tony Abdel-Ahad.

     Abdel-Ahad, joined Dick Smith from Abu Dhabi based Mezzo Middle East two years ago which was prior to the Company being floated. 

    Mezzo is a Middle East furniture Company, prior to that he worked as a regional director for Asteco a Dubai based Middle East real estate Company.
    He appears to have no prior electronics buying or consumer electronics or appliance expertise. 

    Insiders claim that he is related to a senior Dick Smith Director.

    As of yesterday shares in the Company had slumped to $0.775 after trading earlier in the year at $2.29.

    Last week shares in Dick Smith who is believed to be facing cash flow problems running into the peak buying period fell over 35% several institutional investors dumped their shareholding in the Company.  

    Earlier this week we revealed that two more senior merchandising managers have quite the embattled retailer. This follows the of loss Rod Orrock the Director of Buying and Marketing at Dick Smith who quit 14 months after leaving a senior role at Harvey Norman to take a role at the mass CE retailer.

    Orrock said that he left due to “ill health”.

    Games Market Set To Crash

    The games software market is set to decline by as much as 20% a leading analyst has forcast.

    SG Cowen & Co. analyst Lowell Singer in the USA has forecasted a 20% decline in video game software sales during the 2004-2006 console transition, and a 4% decline in 2006 alone.
    Electronic Arts, Activision, and THQ have all guided to software sales that are flat to down 5% for 2006, whereas previously, the consensus expectations were for “at least a modest” sales gain year-over-year, the analyst wrote in a report.

    The analyst cited a “slower-than-expected growth in the installed base of next-generation hardware,” as a reason for the softness in software sales. For instance, Sony (nyse: SNE – news – people ) won’t be releasing the new PlayStation 3 console until late 2006 at the earliest.

    Lowell also cited certain secular risks over the longer-term that could be exacerbating the slowing of sales including a console transition that is “far worse” than the last transition in 1999 to 2001. The analyst also cited an increase in online video game play and criticism of a lack of creativity in the gaming industry, with “no Halo or Grand Theft Auto-type blowout titles launched in 2005.” The analyst said he still recommends Activision shares. “We believe that Activision’s focus on building high-quality franchises, sustaining above-average operating margins and ROIC, and aggressively participating in the expanding handheld market have positioned the company for industry-leading growth and market share gains throughout the next-generation console cycle.”

    His view on Electronic Arts is neutral based on valuation, despite the fact that he sees the company as “the best-run company among the third-party publishers.”The analyst’s view on Take-Two Interactive Software is also neutral. Noting that there are investment positives on the stock, he also listed key concerns in game quality, the company’s “extreme reliance” on Grand Theft Auto as a driver for earnings, low ROIC and the company’s historically poor internal controls.
    Singer also said he views THQ as neutral saying that its growth depends heavily on the average game quality of its new titles for Microsoft’s Xbox 360. “Although we believe that the video game stocks could be volatile over the next few months due to the ongoing console transition, we continue to have a positive long-term view on the group,” the research analyst said.