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

    Smart Office

    BREAKING NEWS: Senior Director Quits Dick Smith After Just 14 Months

    In a shock move, Rod Orrock the Director of Buying and Marketing at Dick Smith has quit 14 months after leaving a senior role at Harvey Norman to take a role at the mass CE retailer.

    Orrock, who was tipped to take on the CEO role at Dick Smith will leave the Company on September 15th according to a leaked email from CEO Nick Aboud to senior Dick Smith management. 

    Aboud claims that Orrock is leaving due to “Health Concerns”. 

    Orrick joined Dick Smith on June 20th 2014.

    Mark Scott has now been appointed to lead the buying team at Dick Smith he will also continue in his role as Director of Operations. 

    In his email Aboud said that he will personally be working closely with Mark and the buying team to “ensure that we continue to operate effectively”. 

    During his time at Dick Smith Orrack has been responsible for the opening of 25 new Dick Smith stores, a move into appliances as well as the setting up of a Dick Smith store at Sydney International airport.

    Intel Viiv Will Drive PC Entertainment

    Australian Company Altech will be among a group of select Companies who will demonstrate for the first time the new Intel Viiv platform at work.

    Altech has been chosen to to show off the first Intel based ePCs based on its much talked about Viiv platform at the Consumer Electronics Show in Las Vegas on January 5.

    Steve Dallman, Intel’s director of channel sales and marketing, said Viiv will combine a media-centric PC platform with a validation program to ensure components are interoperable, targeting marketing, and an effort to increase available content for the systems.

    It’s a launch that Dallman believes will be crucial to the solution provider channel because it provides a flexible platform that begs for customisation and in-home services. “This is the reason resellers will do well with Viiv,” he said. “They can set the functionality and price points based on user desires.”

    The Viiv platform calls for a PentiumD dual-core processor coupled with a motherboard using either an Intel 945, 955x or next-generation Calistoga chipsets; 1Gbit Ethernet; high-definition video; surround sound audio; and the capability to control all devices connected to the system through one remote control device. It also requires support for Intel’s Matrix Storage, technology that lets either a consumer or an integrator configure RAID 5 and data mirroring, and Intel Quick Resume technology that the company promises will turn on Viiv systems as quickly as any consumer electronics device.

    Intel has so far declined to reveal specific spending on its Viiv marketing plan. But the company famously threw $400 million at another high profile launch–is Centrino mobile platform that many solution provider credit with boosting the overall market for notebooks and wireless networking.

    Like the Centrino launch where Intel promised that Centrino-branded notebooks would always work like-branded wireless networks, Dallman said marketing efforts for Viiv will include driving consumers to Viiv-branded products from the Media Center PCs to compatible add-in products, such portable media players or automation products.

    “This is the largest market validation endeavor Intel has taken on,” said Dallman.

    Intel also is setting up calls centers in cooperation with participating Viiv manufacturers to field initial consumer calls. A separate center will be set up for those building and installing the systems, he added.

    By the start of the show, Dallman expects to have 400 of its channel partners including the likes of Altech, Westan and Optima trained on the Viiv platform. Of that 400, he expects 50 to 100 to have Viiv-certified systems. A variety of Viiv form factors are expected at CES, from standard tower systems to high-end devices that are more like consumer electronics products in look and feel–some with LCD screens on the front. Some of these models will be aimed at consumers while others will be focused on audio/video installers and digital home integrators. Price points are expected to range from $2,000 to $7,000.

    Microsoft, of course, started the ePC trend with its Windows XP Media Center Edition, and since then a number of solution providers have not only begun building specialised ePCs but several also have launched separate companies to take advantage of providing in-home integration services to the mass market. But Media Center PCs are still a small slice of overall consumer PC sales and systems builders are hoping that Intel will change that.

    “I look at the Viiv launch as rise in tide that will float all the boats and expand the overall market for entertainment PCs,” said Steve Jarvis, president of Elite PC’s.

    Jarvis is particularly keen on the marketing plan surrounding Viiv and expects a big boost in consumer awareness as a result. Elite PC in 2005 spun off a separate company to focus on ePCs called ZLife. Jarvis said the company is putting together custom sites for integrator partners that want to sell Viiv systems from ZLife. The sites include an onsite Web configure of ePCs that ZLife can drop-ship to integrators or their customers.

    Meanwhile, Shayne Yonce, CEO of CDI and its spin-off Digital Home PC, says the Viiv platform and its RAID requirement is a strong selling point in today’s market, especially as end uses continue to store more and more digital files on hard drives. “It’s not a question of ‘if you hard drive fails’ it is ‘when your hard drive fails,” he says. “When it happens we can make sure you do not experience a devastating event. You still have all your pictures and all your data.”

    Zambroski notes that ACE Computers’ highest end model for the A/V community comes with 3 terabytes of data, enough storage to warehouse tons of music, pictures and movies.

    That’s a lot of space for digital content, but many integrators say it will be needed as more digital services and content are deliver to the home and small office over broadband. Intel will host some content providers at CES endorsing the Viiv platform, but the real push will come mid-year when Intel releases its 1.5 specification with stronger Digital Rights Management (DRM) than currently available in Microsoft’s Media Center Edition, Dallman says. “That’s when we will see some exciting things for Viiv,” says Dezel Lane, CDI’s manager of digital home PCs.

    That is also around the time Microsoft plans to launch its new 64-bit operating system, Vista, which system builders systems expect will give Viiv an additional boost.  The bottom line from systems builders: expect a good Viiv introduction at CES but expect to see some serious growth in the second half of the year.

    Jestar Now Charging Customers For Support Calls

    Budget airline Jetstar appears to be deliberately stinging customers with additional fees by blocking out booking access to add-on services (such as car rental) and then charging fees for simply making a support call.

    Consumers who visit the main Jetstar website to book a rental car are asked to provide several details relating to their booking, flight, airport where the car will be picked up or dropped off along with which car they want to book.

    One also has to provide name, email address and a contact phone number.

    I know, I found out the hard way when I went to book a rental car recently.

    Despite filling in all the fields correctly the ‘Reserve This Car tag was still not letting me book a car online so I did the obvious, I phoned the help number which was located right under the problem booking form. This is the same number that has a big slogan above it saying “Can’t find what you you are looking for online? Give us a call”.

    The operator who took the call found my flight details and made my car rental booking.
     
    Not only did I identify the price of $283 dollars that had come up on the screen via the Jetstar web site, I also identified the type of car that I wanted to rent, along with the rental Company which in my case happened to be Avis.


    Click to enlarge

    The operator said that the booking confirmation was being sent to me by email. When it arrived the bill had gone from $283 to $347.

    When I called back a separate operator told me the reason for the increase was because I had chosen to call the Jetstar help line.

    The operator then said that he was unable to cancel the booking as he “could not get into the system to cancel the car rental booking”. He said I would have to call Jetstar again and ask for another department.

    Andrew Mcginness, a spokesperson for Jetstar, said that the matter would be investigated by Jetstar’s Customer Service team.

    This is not the first time that I have encountered problems with the Jetstar IT operation, during recent trips to Sydney airport I was unable to either barcode swipe the issuing of my boarding pass or use my mobile phone to gain a pass.


    Click to enlarge

    Instead I was forced to queue in a line where out of 8 desks, only two were being used to process hundreds of passengers who had encountered the same problem as me. 

    The Australian Competition & Consumer Commission claims that all additional charges must be outlined by a call centre operator prior to the buyer accepting the price.

    In the case of Jestar this was not done by the operator.

    Foxtel Profits Slump As Netflix Takes Customers

    As expected Foxtel profits have taken a battering falling 8% after the Company was forced to slash prices ahead of the launch of Netflix.

    In the year to June 2015 Foxtel only added 230,000 subscribers Vs more than 1,600,000 subscribers for Netflix who only launched in Australia on the 29th of March 2015. 

    Foxtel’s moves to cut  its prices and counter competition from Netflix comes after Foxtel spent two decades price gouging consumers due to their monopoly in the pay TV market. 

    Chief executive Richard Freudenstein’s decision to almost halve the price of Foxtel’s basic package from $49 to $25 a month in November pushed revenues 1 per cent higher and led to a 9 per cent leap in subscribers over the 2015 financial year.

    Customer churn has been cut from 10.9 per cent from 12.5 per cent in the prior year – the lowest since 2000. Analysts believe this is due to consumers moving to cheaper Foxtel sports packages from premium packages that in the past delivered excellent profits for Foxtel.

    Netflix has already attracted 1.6 million sign-ups and 900,000 paying users to its $9 to $15 a month service, Citi Research estimates.

    “Last year we took the bold step of changing our pricing model to attract more customers,” said Foxtel CEO, Richard Freudenstein. “These results demonstrate that was the right call.”

    Mr Freudenstein said the growth of 230,000 in subscribers was driven mainly by take up of traditional cable and satellite products and that “significant growth continued all the way through the financial year”.

    But Foxtel is counting the early cost of the investment push, with its world-leading average revenues per user (ARPU) for cable and satellite dropping 2 per cent to $93 per month.

    Subscriber revenues were up 2.4 per cent – lower than subscriber growth. Mr Freudenstein said that was “to be expected as we launched in November and therefore most of that increase came in the second half of the year.”

    Foxtel’s 50 per cent shareholder, Rupert Murdoch’s News Corporation, reported on Thursday morning that the pay TV giant’s full-year earnings before interest, tax, depreciation and amortisation slid 8 per cent in Australian dollars.
    News Corp said its equity earnings from Foxtel fell from US$90 million ($121.8 million) for the year to US$59 million.

    Telstra, which owns the other half of Foxtel, said it had received a reduced dividend of $165 million, down from $125 million.

    On a conference call with investors this morning, News Corp said it expects Foxtel to return to growth in its operating earnings in fiscal year 2016.

    Mr Freudenstein said the decline in ARPU was “anticipated as part of the pricing changes”. He said “the vast majority of new customers” took up one or more tiers – such as sport, drama or movies, in addition to the $25 (basic) entertainment pack.

    “This is a great result in an increasingly competitive space. It makes it clear that consumers understand the real benefits that only Foxtel can offer, “he added

    Foxtel faces a growing threat from SVOD services, amid evidence that some customers have abandoned Foxtel’s drama and movie packs – some of them in favour of new, cheaper streaming services led by Netflix. 

    According to News’ accounts, Foxtel’s net income fell 24 per cent to US$232 million from US$304 million as a result of “short-term impacts related to the investment in key initiatives: the new Foxtel pricing and packaging, increased investment in Presto (its own video-streaming service) and the launch of Triple Play (its broadband, cable television and telephony service)”.

    Plasma/LCD Mount With New Twist

    Atdec, the Australian designer and manufacturer of display mounting systems, has launched the Telehook 31-42 Pivoting Wall Mount – the first to allow both landscape and portrait positioning of LCD or Plasma flat panel displays.

    The 31-42 Pivoting Wall Mount is the latest addition to Atdec’s Telehook series of wall mounts. The Telehook series provides a range of practical solutions for mounting all types of large, flat panel LCD or plasma displays.

    “Sales of 30 to 37 inch LCD and Plasma televisions are growing strongly in Australia, and the Telehook 31-42 Pivoting Wall Mount addresses the needs of this market segment by offering consumers a simple, flexible and affordable mounting solution,” said Stephen Crozier, Managing Director of Atdec Pty Ltd. “Users are given the option of displaying their screen in either a portrait or landscape position. It opens up new possibilities for using flat panel displays for decorative purposes, as well as for entertainment”.

    The 31-42 Pivoting Wall Mount also offers users the flexibility of adjustable tilt and pan options from -20 to 20 degrees on the wall.

    The Telehook 31-42 Pivoting Wall Mount is ideal for LCD and Plasma Flat Panel Displays from 31in. (78cm) to 42in. (106cm), weighing up to 50kgs (110lbs). It suits Video & Electronics Standards Association (VESA) compliant displays with 100mm x 100mm (4in. x 4in.) and 200mm x 100mm (8in. x 4in.) mounting hole patterns.  The design features a maximum distance of 81mm from the wall to the back of the display.

    Atdec partners with most of the key AV organisations such as NEC, Hitachi, Fujitsu, Samsung, LG, BenQ, Sharp, Sony, Panasonic, Acer, Dell and IBM designing equipment to suit their individual products. “These relationships and our own research keeps us informed of worldwide trends ensuring our products meet consumer demand and emerging technology requirements,” said Mr. Crozier.

    Priced at $199 (inc. GST), the Telehook 31-42 Pivoting Wall Mount is available through leading audio visual resellers, information technology resellers and major commercial furniture companies such as Thinking Ergonomix and CEDIA members as well as retailers including Harvey Norman and Domayne. Atdec’s Australian State distributors are: Ground Floor Marketing (Victoria and Tasmania), Debetrek ( Queensland and Northern Territory), Sylex (Western Australia), Leader Computers (South Australia) and Corporate Express; New Zealand distributors are Sylex and Metrolink. 

    Product enquiries can be made to Atdec on or www.atdec.com.au.

    EXCLUSIVE: Philips Premium TV’s Will Be Sold In OZ Next Year Claims TP Vision Executive

    ChannelNews understands that JB Hi Fi would have launched the Philips premium range this year however problems with Google’s Android TV delayed the launch of the Philips premium offering.

    This resulted in the mass retailer stocking the Hitachi TV brand that is distributed by Tempo as a replacement for the Sharp TV brand which was pulled from retail stores earlier this year. 
      
    Recently questions were raised about the future of the Philips TV brand in Australia after two leading retailers independently told ChannelNews that representatives of TP Vision had told them that only “cheap” Philips models will be sold in Australia in the future. 

    This has been denied by Erik Kab an executive from TP Vision Australia. 

    He said that it is up to retailers and Tempo the Australian distributor of Philips TV’s as to which Philips premium TV’s will be launched into the Australian market.

    Kab said “the Philips Premium TV range was delayed because of problems with the roll out of Android TV models. At this stage Australia should start seeing Philips premium TV’s by May 2016”. 

    At IFA in September the new Philips UHD 4K AmbiLux TV was revealed along with the Philips 8601 series which is a stunning ultra-thin TV series that Philips has been able to stash in an 18-speaker system made of 16 micro-drivers and two built-in Neodymium subwoofers, all delivering 50W of output. 

    The micro-drivers are hidden inside two 17 mm dark chrome speakers on the left and right side of TV but can be detached for a wireless sound setup. The 8601 also sports Philips proprietary 4-sided Ambilight technology. 

    The Philips 9600 series is not as thin as the 8601 series but it makes up for that in display prowess.  
    In particular, this smart TV comes with support for HDR or High Dynamic Range. 

    The unique Philips technology in the 9600 achieves greater contrast, producing darker blacks, brighter whites, and more vibrant colours than several other TV brands currently being sold in Australia. 


    Several Australian retailers have told ChannelNews that with the right brand investment the Philips could be among the four TV brands sold in Australia.

    The retailers who attended IFA this year where a large range of premium Philips TV were shown to retailers claim that there is a “big market” for Philips premium TV’s in Australia as the brand is “well known” and is seen as a quality European brand despite TP Vision taking a key shareholding in Philips TV operations. 

    A senior Harvey Norman franchisee told ChannelNews that an executive from TP Vision had told them at IFA that in the future only budget Philips TV’s would be sold in Country and “like Philips monitors the stock would be distributed by Ingram Micro or Synnex”.

    “This would be a disaster as there is several cheap TV brands already being sold in Australia. Philips is not a cheap TV brand. Philip audio and TV technology is as good as some of the leading brands” the Harvey Norman franchisee said. 

    When asked why TP Vision only wanted to sell budget TV’s in Australia, the TP Vision executive is alleged to told retailers that both Hisense and TCL were doing a better job of selling “cheap TV’s sand that this is the market where TP Vision wants to compete in the future with the Philips TV brand.

    Tempo the current distributor of Philips TV’s in Australia said that they were keen to launch a new range of premium Philips TV’s this year but stock was not available for the Australian market, they refused to discuss what agreement they had reached to launch new Philips TV’s in Australia. 

    Kab said that in the monitor market Philips was a “tier 2 monitor supplier”.

    He said that the new Philips UHD 4K AmbiLux TV’s will be available for the Australian market in the second half of 2016. 

    COMMENT: Missing Numbers Flaky Results, Why Gerry Harvey Should Quit

    COMMENT: What’s the difference between Woolworths, Coles and Harvey Norman? A lot when it comes to responsible financial reporting and the way in which their operations are run.

    A trip through the annual financial reports of all three companies reveals that a lot is lacking when it comes to trying to glean information from the Harvey Norman annual report.

    There are no breakdowns of how his consumer electronics or IT divisions is performing because Gerry Harvey and his management team don’t want the market to know how each individual division is performing.
     
    Are appliances doing better than IT or are furniture sales propping up the company?

    The fact is we will never know because the inclusion of performance breakdowns would expose some of the weaknesses in the Harvey Norman operation. Talks to analysts will tell you that Harvey Norman is more a retail property company than smart discount retailer.
     
    Unlike Coles, who publish their Officeworks store’s department performance or Woolworths who does the same with its Dick Smith stores, Harvey Norman chooses to hide their numbers and one has to question why?

    Is it because their consumer electronics and IT operations are struggling up against JB Hi Fi, Officeworks, Dick Smith and the likes of The Good Guys?

    Analysts and Investors are now calling for more transparency and better reporting by the retail giant who is suffering on several fronts. It was only 12 months ago that Gerry Harvey was telling the world that Clive Peeters was a “great buy” at $35M, now after losing a million dollars a month from a business that was breaking even when he acquired it, which he intends to shut down at an additional cost of 10 million.

     It was only a few years ago that Harvey Norman had 60% of the Australian IT market, which is the era when brands like Logitech made serious money partnering with the retailers.

    Recently they walked away from Harvey Norman due in part to what is called the “Gerry Tax” which is the 20% that Harvey Norman demands above normal profit margins. There is also the issue of falling sales with Logitech executives claiming that as Harvey Norman demand more from the Swiss Company that sales from his stores were actually falling while climbing with other retailers.

    Once a great discount retailer, Gerry Harvey and his wife Kate Paige, who plays a key role in the Harvey Norman business appear to be on a slippery slope, as Gerry makes ill-timed and  ill-informed comments about online retailing and the lack of a GST Tax.

    Last week he was blabbering Australians should be “as happy as pigs in shit” with low unemployment and the resources boom, but he reckons they’re too frightened to spend – in his stores presumably – and has predicted this Christmas will be a shocker.

     

     Or is it more a case of products being expensive in Harvey Norman stores and when consumers do walk into his stores they get a poor retail experience?

    Melbourne based writer Leon Gettler said that Gerry Harvey is kidding himself if he blames his problems on nervous consumers. The idea of the so-called cautious consumer is not what it’s cracked up to be.

    He says that despite the signs emblazoned all over the front of shops advertising 30 per cent, 50 per cent and 70 per cent discounts, no one is buying. But that’s not about consumers being too scared to spend: it’s a failure of his retail management strategy.

    Blaming his poor performance on frightened consumers is a cop-out,  as yesterday’s ABS numbers reveal household spending is not weak at all.

    The hard reality is that Harvey Norman appears to be more a property company than a smart retailer. His recent 9% climb in profits was more attributable to a revaluation of his property portfolio than it was selling more products.

    Gettler claims that a closer analysis of GDP figures shows that household spending is doing well. Retail spending accounts for only 32 per cent of total household spending – in other words, more than two thirds of household spending is done outside the retail sector. 

    Closer analysis of the data suggests that while retail sectors are experiencing serious deflation and weak spending volumes, households are spending more on non-retail goods and services.

    Gerry Harvey is today being hurt by people and organisations that are smarter than he and his management team.

    Well known for their bullying of vendors and distributors the Harvey Norman team is constantly being outperformed by the likes of JB Hi Fi who started out in 1974 selling audio equipment and records.

    They are now a major seller of mobile phones, home theatres, computers anything with an Apple brand on it and above all content such as music, video and games products that are hard to find in a Harvey Norman store.

    JB Hi Fi recognised that goods under $99 are often the bait that draws consumers into their stores.

     

    Consumers who walk in to a JB Hi Fi store to buy an iPad, Phone or the latest Samsung offering are tempted by racks of cheap CDs and DVDs. In an age when retailers are worried about the Internet, JB Hi Fi is launching a digital music streaming service followed by a video streaming service.

    Last week when I walked into a large Harvey Norman store in Sydney and asked for assistance the retail assistant told me that did not work in the IT department and that she would find someone who did, 10 minutes later I was still waiting.
     
    What Gerry Harvey needs is a new younger management team, a team that have the passion and the nose to turn his business around. Most Harvey Norman executives today are clones of Gerry Harvey and he is a force who back in 1997 said the Internet was a “fad.” Since then he has fought the Internet day in day out as he has tried to hold onto consumers.

    What he needs to do is retire and the sooner the better the business will be.

    Windows Vista is next OS

    The name of Microsofts next consumer operating system has been revealed. It will be called Windows Vista.

    Microsoft’s next consumer operating system to replace Windows XP will be called Windows Vista. The secret was revealed in a brief video message published by Microsoft on Friday. The first beta of the software is scheduled to be released on August 3 2005. Microsoft’s next-generation operating system shed its codename early Friday when Microsoft posted a 68-second video message on its website that had the sole purpose of introducing the name of the final product:

    Microsoft associates the terms “clear”, “confident” and “connected” with the new operating system, hinting to various new features of the software – including a new graphics engine, more multimedia capabilities, improved organisation of information, more security, and easier to use networking features for various devices around the house. The first beta version of the software is heading towards IT professionals and developers on August 3, according to Microsoft. The final product will be released in the July 2006 timeframe, which will be preceded by at least one release candidate (RC) and a second beta, which is rumoured to become available sometime in November of this year. According to Microsoft, the video message was taped at a recent briefing for the firm’s global sales and marketing staff.

     

     

     

    Harvey Norman + Dick Smith Online Back End Up For Sale

    EBay is set to sell eBay Enterprise the owners of Magento the Company that powers some of Australia’s largest retail web sites including the backend of the Harvey Norman web site.

    Among other users of the Magento retail software offering are  Bing Lee, Dick Smith, Winnings Appliances and Big Brown Box as well as IKEA and several leading International brands who sell into Australia. 

    Private-equity firm Permira is tipped as the organisation that is interested in buying eBay Enterprises for a reported around $900 million, according to people familiar with the matter.

    The deal, which was being finalized early today, could be announced as soon as Thursday US time (Friday Australian time) when eBay is scheduled to release second-quarter financial results.

    EBay also plans to complete the spinoff of its PayPal payments unit on Friday.

    EBay has been seeking a buyer for the Enterprise unit, which helps power online retail sites for companies such as Harvey Norman, IKEA , since at least January, when it said it also could also spin it off.

    The unit suffered a blow last week when Toys “R” Us  one of its larger customers, said it would take its U.S. business in-house by mid-2016.

    An eBay spokesman declined to comment. New York-based Permira didn’t immediately respond to a request for comment.

    According to the Wall Street Journal EBay  also been in talks recently with private-equity firm Thomas H. Lee Partners LP to sell the unit for as much as $1 billion.

    Resolving the fate of eBay Enterprise, formerly known as GSI Commerce, is among the final loose ends the company hoped to tie up before its new life as a stand-alone company.

    The roughly $900 million price would be less than half the $2.4 billion that eBay paid in 2011 for the unit. In the hopes of securing a deal, eBay had extended the prior deadline of June 30 to Wednesday, one of the people said. The people said there was no guarantee a deal would be reached.

    COMMENT:Why Sharp Is A Massive Basket Case

    Sharp Australia hasn’t got much left in the consumer appliance market, they got out of the TV market last year, not because their TV’s were inferior but because of poor marketing resulting in a lack of uptake by consumers.

    Now their appliances business is on life support as their parent Company is set to be flogged to Taiwanese Company Foxconn, in a multibillion dollar deal that could well see the Companies consumer products disappear from Australian shelves.

    Sharp make extremely good products but they don’t know how to price them or market them because of a combination of poor Japanese management and local management, who don’t have a clue when it comes to delivering cut through marketing. 

    Sharp management have failed dismally resulting in lost jobs, and a once great brand relegated to the back end of stores. 

    The Sharp Australia web site which is a low cost way for the Company to market their products.

     But the problem is that this site is shocking and local management, don’t have a clue when it comes to social media marketing, which in the USA is seriously driving sales for Sharp.


    Click to enlarge
    Sharp Australia Intro Page


    Click to enlarge
    Same Product Page On the Sharp US web site

    Click to enlarge
    Sharp Australia product page, 1999 type design.

    Click to enlarge
    Same type of product page at Sharp USA with scrolling benefits.


    In the USA Sharp appliances are top of mind and growing, but when it comes to online the difference between the Sharp Australia web site and the US site, the difference is like chalk and cheese.

    While the Australian web site looks like something from the early days of online the US web site is engaging and designed to deliver information for consumers.
     
    Deloitte Australia Research shows that 65% of consumers are going online to search for information prior to shopping, they either visit a retailer’s web site or go direct to a vendors site who redirects them back to a retailer to buy or like Sharp in the USA sell the product direct. 

     According to a recent study by e-commerce analytics company Clavis Insight, Sharp trumps its top five online competitors in the big US market, including Panasonic who are the #1 microwave supplier in Australia in five key metrics: availability, image presence, content, keyword search and customer ratings.

    With 17 percent of market share by volume in 2015, according to Euromonitor, Sharp leads the pack with strong breadth and depth of distribution among online appliance retailers analysed in the study.
     
    Specifically, at least 15 Sharp models were offered by the trio Amazon, Target.com and Walmart.com – while Target’s e-tail site carried 33.

    What’s more, the brand outperformed its peers on both search performance and image presence, offering multiple product views on a large majority of its product pages. 

    This must be embarrassing for Sharp Australia staff who believe marketing is still about giving retailers a bundle of cash and expecting them to build the brand and market the product using catalogues, store visits and online. 
    Along the way they slap together some external marketing to demonstrate to retailers that they are actually conducting some form of external marketing.

    Today a strong web site that promotes a brand as well as products is a critical part of any marketing mix.

    Also critical is video as 63% of all transactions at web sites like Harvey Norman and JB Hi Fi are coming from portable devices such as a smartphone or tablet. Consumer today want to simply press a button, watch a video and then make a decision as to their next move.

    Sharp’s problem is not about money, it’s all about deadwood.

    What Sharp Australia needs is a Young aggressive digitally savvy marketing team that can ID the right products for Australia and then aggressively market them.

    They need to give the brand CPR so that when it comes back to life consumers actually want to engage with the brand. 

    At one stage Sharp branded products were an object of pride for both Australian and Japanese consumers.

    Sharp started to come unstuck in 2005 when Japanese management started to believe that the brand was invincible.
     
    They believed that their new LCD/LED TV production plant at Kameyama was the be all of TV production plants.
     
    The only problem was that the Japanese management was only watching the Japanese markets and not overseas markets like Australia or the UK and the USA, while at the same time they failed to capture orders from third party TV Companies to manufacture display components.

    This resulted in the Company racking up massive losses.
     
    Even while the plant was pumping out product, it was seriously in debt due to competition from other TV manufacturers, including Chinese and Korean manufacturers.
     
    The blinkered world view that still exists at Sharp Australia today has destroyed a once great brand. 

    Now the Japanese are fretting at the loss of the iconic brand to a Taiwanese Company Foxconn who has made a name for themselves making goods for Apple. 

    at the heart of Japan’s reluctance to let Sharp be sold to Foxconn is the bile building up in the throats of Sharp management and Japanese Government official’s that the know how once owned by a great Japanese Company is set to fall into the hands of a competitor. 
    The anxiety comes from a deep feeling that denies the ascendance of Taiwan, China and South Korea in realms where Japan once reigned. 

    Japanese media never seriously discuss the fact that companies such as LG, Samsung and Haier now dominate the global home electronics field.
     
    A few pundits and journalists have made the case that not only does Sharp’s likely sale to Hon Hai not signal the end of the world, but that it could turn out to be a good thing for Japan. 

    During a recent Japanese TBS Radio discussion, listeners sent in questions betraying their nervousness over the deal.

    One listener remarked that if Hon Hai buys the ailing company, Sharp will merely become a “maker of goods.” Atushi Osanai a Japanese academic told the listener that, in fact, Hon Hai was buying Sharp because it admires the company’s knack for new ideas.

    What he failed to communicate was the fact that Japanese Companies are making great products but they are failing dismally when it comes to marketing the products.
     
    Sharp who does not have much of a profile outside Japan due to its lack of initiatives is doomed to becoming a supplier of components. 

    Japanese electronics makers “have never had an overseas strategy,” according to Osanai, unlike Japanese car makers. He claims Hon Hai will give Sharp that chance, something the Innovation Network Corporation of Japan who also been bid for the Company would not have been able to do.

    Foxconn says it will not sell off any part of Sharp, though that could change once the financing dust has settled.

     Japanese media say that Hon Hai wants Sharp for its display technology, but there is nothing special about Sharp’s LCDs, which have become a commodity because Sharp management were unable to sell the superiority of their panels. 

    In truth, it wants to get into the IOT (Internet of things) business, by producing home appliances that can connect to the Web, and for that it needs Sharp’s know-how. Hon Hai’s rival, Haier, bought General Electric’s appliance business for the same reason.

    Softbank another big Japanese Companies popular robot, Pepper, is manufactured by Foxconn another fact the media rarely mentions but one that is central to the issue of Sharp’s worth to the company. “Hon Hai is just like Pepper,” said Osanai. “You can tell it what to do, but it won’t come up with ideas on its own.”