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 60 of 91

    Smart Office

    HTC Sales Falls 49%, $345M In Losses After One M9 Problems

    HTC who is believed to have the ‘Up For Sale’ sticker out has reported a 49% drop in revenue and a net loss of $345M loss.

    In the first half of 2015 sales have fallen 57.7% the profit fall follows four quarters of slight net profits.

    The Taiwanese Company has been hit by plummeting smartphone sales and valuation losses after production lines that were ramped up for the new One M9 were left idle.

    HTC has announced a strategic shift to sell more mid-priced phones in emerging markets as opposed to more expensive ones in markets like Australia.

    They have also moved to strip manufacturing costs.


    Click to enlarge


    In the second quarter, its revenue totalled NT$33.01 billion, almost half the NT$65.06 billion it fetched in the second quarter of 2014.

     HTC doesn’t disclose its shipment number, but the company has said it has closed some of its production facilities as sales have dropped and as it has outsourced some of its manufacturing. 

    The Wall Street Journal said that HTC was a top Android smartphone maker a few years ago, but its return to losses indicates how second-tier smartphone makers are struggling in a maturing market.

    Low-cost smartphone makers, such as Xiaomi who does not operate in the Australian market because it is “too small” according to their Chinese executives, are grabbing emerging-market share quickly at a time when global smartphone shipment growth, particularly toward the high-end is slowing.

    Despite praise for the sleek design of HTC’s flagship device for this year, the One M9, some analysts were sceptical, citing the phone’s incremental hardware upgrade from its One M8 last year.

    HTC’s shares in Taipei sank to a record low of NT$71.10 on June 30, compared with an all-time high of NT$1,300.00 in April 2011. 

    Chairwoman Cher Wang, who returned to day-to-day operations last year and has also been doubling as chief executive since late March, has said the company “is moving beyond the smartphone business.” It has recently launched a fitness band and a virtual reality device in overseas markets but not in Australia where the Company is trying to set up a sales network of retailers.  

    Toxic Relationship Between Dick Smith And Bankers Led To Collapse Administrators Set To Claim

    A falling out between Dick Smith’s bankers and senior management at the mass retailer was fatal, an administrators report into the Companies collapse is set to report.

    The administrators from McGrath Nicol believe that the relationship between the banking syndicate, led by National Australia Bank and HSBC was so toxic that the bankers simply pulled the plug on the mass retailer, despite evidence revealing that the Company could have survived had an injection of capital been injected into the ailing business.

    Nick Aboud who was struggling to hold onto senior management and buyers at the mass retailer was one of the key negotiators with the banks along with Chairman Rob Murray.

    According to Fairfax Media Dick Smith’s relationship with National Australia Bank and HSBC was barely six months old when the retailer announced a $60 million inventory write-down in late November and revealed it was “unable to re-affirm the profit guidance previously provided”.

    Dick Smith management who have been accused of concealing trading and sales information from suppliers failed to alert the banks about the impairment charge with one insider claiming that “this was a fatal mistake”. 

    Desperate to raise cash the management team is believed to have approached both Anchorage Capital the Company that initially floated Dick Smith raising over $500M dollars along with overseas investors.
     
    Fairfax Media claim that the partnership with the banks who in December had moved their own management team into Dick Smith head office was further strained by Dick Smith’s repayment to Macquarie in December on a $30M unsecured loan provided to cover the upfront payment for Apple stock after the tech giant withdrew supplier credit in about October.

    When the Company finally collapsed and Ferrier Hodgson was appointed as receivers it was revealed that the Company had been unprofitable for months and that Dick Smith owed the Bank and suppliers over $400M.

    One source told Fairfax that the  banks “hated surprises” and NAB and HSBC were hit with several in quick succession from Dick Smith.

    He said the bank was “shocked” by the stock write-off and the payment to Macquarie further inflamed the situation.

    Dick Smith’s relationship with its banks is believed to have played a significant role in the collapse of the business.

    “NAB was annoyed Dick Smith paid off an unsecured lender [Macquarie] ahead of reducing its facility with it, a secured lender,” he said.

    The Federal Court has granted Dick Smith’s administrators McGrath Nicol a six-month extension to the schedule for its second creditors meeting, which means it won’t be held before August 9.

    The receiver’s first report on Dick Smith’s New Zealand operation has identified a $NZ98 million shortfall in the funds available for priority creditors, and Ferrier Hodgson said it could not estimate how much of the $NZ32.8 million in stock would be recovered through its current fire sale through the network of 62 stores.

    Sony Set To Close Online Store New Direct Sell Model To Be Rolled Out

    Sony is set to close their current online store, no reasons has been given for the sudden announcement.

    The struggling Japanese Company said that the store will be shut down on the 28th of August. 

    Customers have been warned if you have any gift cards or if there are some products that you’d like to purchase through its website, you should probably do so before the 28th of August.

    Insiders have told ChannelNews that the Company will later this year launch a brand new online site aimed at capturing a greater share of “consumer retail” business in Australia a move that is set to upset the specialist camera channel and mass retailers currently selling Sony sound gear, cameras and TV’s. 

    The Sony email announcing the changes said “soon unveil a new online product showcase and more ways to shop.”

    Some of the comments made on various forums claim that Sony’s online store was always a bit of a mess, while others did not even know Sony had an online store to begin with.

    Pioneer Slammed By Channel Future Looks Grim

    Pioneer Electronics has been slammed after they announced earlier today that they had done another flip flop in a desperate effort to cement themselves a position in the Australia display and sound market. After taking an each way bet between the specialist and mass channel the Company has now decided to concentrate on the specialist channel in an effort to deliver bottom line profits over revenue and losses. However the specialist channel may not support them.

    Interviews done with the specialist channel by ChannelNews reveal that they are sceptical claiming “They don’t have the balls” to pull it off. Others have said “I will believe it when I see it”.  “They are more interested in the mass market and have well and truly screwed the specialist channel in the past you only have to look at their web site to see this”.

    During the next few months the Company claims that they will roll out an arsenal of new products including new plasma TV’s, a new generation of LCD TV’s made by Sharp as well as new home theatre kits, and high end sound systems all aimed at the specialist channel.

    To facilitate the move newly appointed Pioneer Electronics Australia Managing Director Yasuo Sakuma has restructured his management team and is set to start rolling out new products however the specialist channel that Pioneer desperately need to support them do not trust Pioneer claiming that “Every year they change their mind in 2009 it will be back to the mass channel”.

    Len Wallis of Len Wallis Audio in Sydney said “I don’t know whether they have the balls to pull this off, one minute they are in the specialist channel the next they are chasing mass retailers. They are constantly out of stock despite having excellent products”. He said.

     

    He added “I have dealt with Pioneer for 30 years and they have constantly changed their loyalty. They very quickly drop their pants when the big boys call their bluff and say jump they jump”. 

    Adam Merlino a director at Pioneer specialist reseller Audio Connection in Sydney said “I will believe it when I see it. Their stock levels are always low and right now we have back orders for Pioneer plasma screens that they cannot fulfil”.
    Peter Alexandrie of Audio Lifestyle in Melbourne who is also a specialist Pioneer dealer said “I don’t trust any of them. We set up nice show rooms, we spend hours of our own time going to training at Pioneer and they then go out and sell to the mass retailers who sell their product below our buy in price. The mass retailers know this and us as a benchmark so that they can sell under our plasma screen price”.

    Another Sydney dealer who has dealt with Pioneer for 14 years said “It is all bullshit. They are in deep trouble and they now expect the specialist channel to bail them out. You only have to look at their web site where they have a preferred partner indicator. If you type in for example a 2000 code postcode the site spits out Pioneer partners within a 5klm radius. Not one of the top 10 is a specialist reseller it is all Bing Lee, Harvey Norman, JB Hi Fi and Domayne. There is your answer to what Pioneer think of the specialist channel”.

     

    Mark Anning Marketing Manager for AV at Pioneer Electronics said “We have some bridges to mend. The past is the past we can only make decisions now and move forward from it” he said. “We are going to have face to face meetings with many of our partners in the specialist channel over the next few weeks”  Anning also revealed that Pioneer will not have new plasma or LCD TV models until the end of the year and that during that period they will roll out new sound and home theatre systems.

    ChannelNews has conducted an extensive interview with Pioneer this will appear during the next few days.

    AS TIPPED: Kogan Snares Dick Smith + Move Brand Names, 1M Customer Database + Online Operations

    As we exclusively tipped last month the Dick Smith and Move brand names along with all trademarks and online operations as well as the names and address of over 1M Dick Smith customers has been sold to online retailer Ruslan Kogan, several Companies sought to buy the package.

    The deal is set to be used to spearhead a $300M float by the online retailer, who still plans to keep his Kogan online brand. Currently Kogan is working with investment banks UBS and Canaccord Genuity to prepare a public float in the second half of this year.


    Kogan has told executives from the receivers Ferrier Hodgson, that the Dick Smith brand name will have “more appeal” to investors when he floats despite the fact that it is seen as a failed brand. 

    Currently the Dick Smith online business is generating between $85 and $100 million a year. 

    The acquisition includes all online operations in Australia and New Zealand as well as the Dick Smith and Move customer databases, which could create problems for consumers who face being bombarded with emails from the Kogan operation as opposed to the prior Dick Smith Company.  

    The deal was secured after three weeks of negotiations with Ferrier Hodgson the receiver of the failed Dick Smith retail operation.

     ChannelNews understands that Kogan has paid less than $10M to secure the deal.

    What is not known is whether the acquisition of the tarnished Dick Smith brand name will impact his Kogan online operation, or whether large consumer electronic brands who sell the bulk of their product via Harvey Norman and JB Hi Fi will actually deal directly with Kogan who currently is forced to buy most of his branded stock from either overseas grey marketers, or distributors who are adding an additional margin over what JB Hi Fi and Harvey Norman pay. 

    ChannelNews has been told by one major retailer that representation has already been made to several key brands regarding the supply of stock to Kogan.  

    According to sources Kogan sees the Dick Smith brand as the centre pin of his planned float.   
    Kogan who refuses to make his financials available claims that the deal will boost his sales by $90M.

    Kogan claims that Kogan.com is generating annual sales of close to $250 million however these revenues are unsubstantiated.  

    “Dick Smith is one of the most iconic Australian retail brands and we will be able to leverage the millions of dollars we’ve invested into online retail systems and architecture over the last decade to sustainably run the business,” Mr Kogan told Fairfax Media.

    Mr Kogan acknowledged the damage to the Dick Smith brand since the retailer’s collapse in January and said he would invest to rebuild consumer trust and make Dick Smith’s online offer “better than ever.”

    “Ultimately, a brand grows when it delivers on its promises. We will work tirelessly to exceed the expectations of every Dick Smith customer with a beautiful shopping experience,” he said.

    Clive Peeters Debt Balloons To Over $140M

    LG Australia who in the last financial year only managed a profit of $13K from nearly a billion dollars turnover is facing the prospect of $25M exposure, after the collapse of retailer Clive Peeters with debts in excess of $150 million.

    In the consumer entertainment category  Sony, Panasonic and Sharp are also exposed, while Samsung is believed to be free of any exposure after the Company refused to deal with Clive Peeters. Several vendors including LG have credit insurance with QBE Insurance who is believed to be exposed for tens of millions of dollars.
    Between 2007 and 2009 the Company failed to identify a shortfall of $20M which had been systematically stolen by a former Payroll Manager Sonia Causer, who over the two year period was able to establish fake employees due to a lack of Company security procedures.
    Greg Smith the CEO and major shareholder in Clive Peeters, was the former CEO of the Vox Retail group which owned Billy Guyatts and the Chandlors chain of stores. This retail group collapsed after expanding in a similar way to what Clive Peeters has been trying to do with limited capital.
    Back in 1970 Smith was a partner in a medium-sized accounting firm that looked after the interests of Billy Guyatts. In 1971 Smith quit accounting to become CEO of the Vox retail group.
    In an effort to expand Smith urged his board to buy the Rick Hart group in Western Australia as well as the Michael King stores in Victoria.
    As a result of Clive Peeters being placed into administration the Rick Hart Group in WA has been placed into  voluntary administration.
    Next week receivers Phil Carter and Daniel Bryant of corporate advisory firm PPB is set to try and sell Clive Peeters. Terry Smart, CEO of JB Hi-Fi, said that his group is not interested in buying the Clive Peeters business. He said, “This has been coming for a long time, the retailer is of no interest to us, however, it is not good for the industry”.  
    Phil Carter of PPB said that he will conduct a formal sale of Clive Peeters’ assets, and had already received a significant number of inquiries from potential buyers. Mr Carter noted that some potential purchasers wanted to buy the entire business as a going concern.
    “The initial signs certainly appear promising,” he said.
    According to the Australian newspaper Gerry Harvey, executive chairman of furniture and electrical chain Harvey Norman, yesterday said he would be interested in buying several of Clive Peeters’ more profitable stores, but not the entire company.
    “They have so many loss-making shops that can’t be turned around,” Mr Harvey said.
    , Mr Carter said PPB was “stabilising the business operations”, with all 1300 staff remaining in employment across the network of 45 stores and three warehouses. “We will be trading on a business-as-usual basis as far as possible in the circumstances.”
    Several retailers have said that “If no one sticks their hand to buy Clive Peeters the industry could witness as major fire sale” similar to what happended in the USA when Circuit City collapsed. This they say could impact both Harvey Norman and JB Hi Fi as well as Dick Smith. 

    EXCLUSIVE: Telstra Management Report “Massive Failure” For Sony Xperia Z3

    Up to 70% 0f Sony Xperia Z3 smartphones have failed when consumers have tried to reboot their smartphones after they have been activated at Telstra stores according to Telstra sources.

    ChannelNews has been told that “hundreds” of Sony Xperia smartphones have “gone dead” within days of the device being activated on the Telstra network.

    Telstra management who spoke to ChannelNews on the basis that we did not reveal their identity said that Sony were well aware of the issue as they had replaced the problem devices. 

    Sony who has a track record of trying to manipulate the media is refusing to acknowledge the problem.

    Initially ChannelNews spoke to Joshua Velling Account Director for Telstra at Sony Mobile Communications.

    He did not deny the failure.

    He said “I cannot make a comment on this issue, I have to pass you onto our PR Company Hausmann”. 
     
    A spokesperson for Hausmann said after contacting Sony, “Sony does not comment on rumours or speculation”.

    ChannelNews has been shown Telstra incident reports relating to the problem.

    The issue is believed to have arisen in the second quarter of 2015 when Sony Mobile Communications only managed to sell 14,350 units.  

    New smartphone sales figures issued by IDC reveal that Sony, only managed to sell 14,350 of their current model between April and June Vs 797,661 Apple iPhones and 760,001 and Samsung Galaxy smartphones.

    The Company is not saying whether their biggest customer Telstra stopped ranging the Xperia smartphone until the problem was fixed.

    Telstra store managers said that there was a period when there was “no new Xperia smartphones available” in stores as Sony moved to fix the problem.

    The Sony Xperia 3 has been a problem smartphone for Sony. Issues reported around the world include, touchscreen unresponsive or glitchy, Texts won’t send, there has also been overheating problems.


    Click to enlarge


    Other problems include a bug, where no notifications appear on the lock screen, rapid battery drain, call and notification volume too low, Wi-Fi slow, won’t connect, or dropping
    Issue and the Z3 failing to turn on.

    A Telstra manager said The XperiaZ3 has been a problem smartphone from day one. We have had constant problems. One of the biggest was when customers took the device home and then found that it would not switch on. We simply sent them back to Sony who supplied a replacement Xperia Z3.

    We are still waiting for a response from Telstra. 

    Smart New Wireless Speakers To Be Launched By Cambridge

    Cambridge Audio is set to launch a new AirPlay and Bluetooth-enabled speaker system in Australia called Minx Air.

    The Cambridge Audio Minx Air 100 and 200 are set to be sold via specialist dealers in Australia. They allow a user to stream music from a smartphone or tablet.

    The smaller Minx Air 100 model features two BMR (Balanced Mode Radiator) drivers, while the Minx Air 200 also adds a 6-inch subwoofer into the mix.

    The speaker systems also have a Minx Air companion app, which allows users to access over 20,000 internet radio stations, as well as controlling volume and EQ settings.


    Click to enlarge

    Built using Cambridge Audio’s patented BMR speaker technology, the Cambridge Audio Minx 200 features Digital Signal Processing capabilities that combine with the speaker to produce louder and fuller sounds than similar sized traditional speakers.

    An on-board subwoofer offers enhanced bass tones and 200 Watts of sound power will bounce sound around any room despite the Cambridge Audio Minx 200’s compact design.

    The compact speaker system connects to the majority of smart devices, including any Bluetooth enabled phone, tablet or computer. Utilising the Apple AirPlay technology, the Cambridge Audio Minx 200 will synch with desktop based iTunes libraries and to Apple devices like the Apple iPhone 5 or iPad mini.

    Once set-up, any synched device will remain connected and play any audio application through the Cambridge Audio Minx 200 speaker system automatically. Music streamed from services such as the BBC iPlayer Radio, Spotify or YouTube can also play through the Cambridge Audio Minx 200 via any of the connected smart devices.

    Dick Smith Stores Struggle As Takeover Claims Emerge

    Dick Smith is facing the real possibility that several of their unprofitable stores will be closed down in the new year with several store managers claiming that foot traffic into their stores is extremely “slow”. We can also reveal that an Asian group is currently running a ruler over the struggling retail group.

    A visit yesterday to several Dick Stores in Sydney revealed poor traffic and in some stores during the peak lunch time period there were no customers queuing to pay for goods.  

    At 1.00pm yesterday at the Dick Smith George Street store ChannelNews saw only one person pay for goods, the store was primarily empty despite it being one of Dick Smiths flagship appliance stores. 

    It was also the same at the Company’s other CBD store located right next to Myers and one of the CBD’s biggest food courts.


    Click to enlarge
    Dick Smith George Street store yesterday, during peak lunch time period


    Click to enlarge


    Click to enlarge
    Right across the road from the Dick Smith store consumers stretched back to the door as they waited to pay for goods.

    Click to enlarge
    JB Hi Fi Store George Street Sydney


    One store manager at a Dick Smith store said “It’s been like this for weeks, we are not getting the traffic into stores despite Dick Smith delivering good discounts. I think there is a perception that Dick Smith is all about online discounts with stores being given a miss. We are carrying a lot of house brand products that also puts people off despite the fact that we also have a lot of quality brands”. 

    He added “Some managers are concerned that they and their staff will be out of a job after Christmas as some stores are not profitable and the Company is not in a position to carry unprofitable stores”.  

    10 minutes after visiting the Dick Smith CBD stores we visited two JB Hi Fi stores. At JB Hi Fi in the strand consumers queued the whole length of the store to pay for their purchases which included gaming consoles, smartphones, new two in one notebooks and covers.

    Internally Dick Smith management have moved to look at restructuring their Hong Kong sourcing office after buyers at the besieged Company complained about the amount of “house brand” stock being shipped into Australian stores without consulting buyers in Australia. 

    The General Manager of the Hong Kong Office for International Sourcing at Dick Smith Electronics is Tony Abdel-Ahad who last week flew back to Hong Kong after a visit to Australia.

     Abdel-Ahad, joined Dick Smith from Abu Dhabi based Mezzo Middle East two years ago his experience is in UAE real estate and not consumer electronics. 
    This has prompted senior Dick Smith management to now review their sourcing operations.  

    Yesterday Dick Smith shares slumped to $0.75 after selling 12 months ago at $2.29.

    ChannelNews has been told that an overseas investor is currently looking at moving on the group with a view to acquiring the Company. Sources have said that the share value of the Company has to fall further before a takeover move is triggered. 

    “They have the money and are cashed up. They believe that the Company will struggle to lift sales during the Xmas New Year period due to stock problems. It’s anticipated that the stock will fall further when they announce their third quarter results, that’s when a takeover move will be triggered” the source said.

    ChannelNews has been told that the group will dump several consumer electronics lines along with appliances in favour of taking on Jaycar and Super Cheap Auto.

    “The Asia based group believe that they can reposition Dick Smith as ‘The Gadget Shop’ with revenue being generated by selling products similar to what is being sold by Jaycar and Super Cheap Auto. Dick Smith has better locations and by focusing on technology and electrical products including toys it’s believed that they can turn the Dick Smith stores around”. 

    Digital Conman Leaves Another Debt Trail As Third Business Goes Belly Up

    He’s been described as a digital smartarse and conman, Jamie Silver, the founder and managing director of the Melbourne-based Dcodr Agency has done it again, gone broke leaving behind millions of dollars’ worth of debt.

    Among his clients were retailers, consumer electronic Companies as well as brands like Albi, Go Switch, Wingman Airport Shopping. 

    Silver, who is already looking for “The next opportunity” has been labelled a “conman” among the digital agency world after going broke with two prior Companies.

    Several Companies are now chasing silver for unpaid bills. also left in the lurch are Dcoder staff. It’s also tipped that ASIC is set to take action against Silver a move that could see him banned or stopped from being involved in Companies in Australia.  

    Jamie Silver


    Silver and Dcodr hit the headlines last year after a developer took over the website of its client, Goswitch, accusing him of failing to pay an outstanding invoice, his latest debts are said to total over $200,000.

    Silver is already denying that he has left behind a mountain of debt or that he owes $200,000. He claims that he is still trying to collect money from clients. 

    Silver also claims that he is a victim of a fraud.

    Visitors to the site that was hacked were greeted with the words “Pay Up Jamie” plastered across the home page along with the message: “Jamie at DCODR didn’t pay the developer of this site and has an outstanding balance of $2975.”

    The hacker also uploaded a video of Rihanna’s music video Bitch Betta Have My Money.

    mUmBRELLA claims that in December 2014, Silver took a company with an almost identical name to Dcodr Agency – Dcodr Pty – into voluntary liquidation with the business owing more than $532,000 to 12 creditors.

    A report into the collapse by liquidators PPB Advisory was sent to the Australian Securities and Investments Commission (ASIC) “detailing offences that may have been committed by the Company and/or its officer”.
    The liquidator said it was unlikely any creditor would receive any money.

    ChannelNews has been told that Silver has been door knocking several consumer electronics distributors as well as specialist Hi Fi and consumer electronics retailers trying to get new work. 

    Official documents show that in September 2014, three months before PPB was called in, Silver had registered Dcodr Agency with ASIC, a business which has continued to trade.

    Silver also owes money to several IT contractors.

    Ronnie Davies, vice president IT Solutions at Optimal Transnational, a company specialising in outsourcing and offshore solutions, told Mumbrella his firm is owed $13,000.

    “We were told by Jamie Silver back in November that he was unwell and that his wife would be taking over and that she would be paying our invoices. But we have not been paid.

    Along with the collapse of Dcodr Pty, it also emerged that another of Silver’s businesses, Pixel Light, also called in liquidators with almost $550,000 owed to five creditors when it went to the wall.

    Pixel Light had its roots in another of Silver’s enterprises, Clear Light Digital, a company he had jointly founded in 2005.

    According to Mumbrella, Former employees have provided information to ASIC accusing Silver of phoenix activity, a practice which involves the intentional transfer of assets from an indebted company to a new company to avoid paying creditors, tax or employee entitlements.

    ASIC said it was unable to confirm or deny whether it was investigating Silver.

    Silver also denied he was planning to set up another agency called Airside Digital.