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; } } Oonagh Reidy, Author at Smart Office - Page 41 of 116

    Smart Office

    Vodafone Is Vodafail(ing), Say Consumers

    New website, Vodafail.com has been set up by disgruntled Vodafone customers in response to the litany of service issues users have been experiencing in recent weeks.As reported on Smarthouse earlier today, users who have been reported as experiencing ongoing problems with Vodafone’s mobile service, including call failures, slow data speeds and poor reception, are not necessarily entitled to end their contract, the Australian Competition and Consumer Commission said in a statement.

    The ‘share your pain’ section of the newly established site contains comments such as “I live in North Sydney and yesterday (16th Dec) rang my wife twice while she (also a Vodafone user) was in a taxi coming in from the airport. Her phone rang through to voicemail but she never heard it ring and she was holding it in her hand. There is no way the Vodafone problems have been fixed.”

    Others had less to say but it is clear that despite Vodafone’s claim to the contrary, the network problems still exist.

    “One freaking hour on the phone to Vodafone AU WORST SERVICE EVER! I’ve been on hold for 45mins of them. They can’t fix my problem!,” said another Twitter feed on the site.

    Both Vodafone’s branded Facebook and Twitter pages have also been flooded with complaints.

    The telco attributed the recent problems to unstable software issues, which meant slower 3G data downloads.

    Affected customers would be offered refunds, Vodafone chief technology officer Michael Young, said earlier this month.

    Telstra: Fixed Line Is Broke – Lets Go New

    Something is rotten in the Telstra basket – fixed line phones. And how badly it has gone off it will be fully revealed this week.In accordance with earnings guidance issued last September, the Telco’s profits before interest, tax, depreciation, amortisation (EBITDA) looked set to fall by “high single digit percentage” this year, with a free cash flow guidance of between $4.5 billion to $5 billion.

    However, this original downgrade now looks set to free fall into low double digit territory, according to analysts at Deutche Bank who predicts Telstra profits for second half of last year will be $4.7bn – a  12.5 per cent drop. 

    This massive fall is partly due to its declining phone line business, which thanks to massive mobile and broadband uptake has meant consumers are phoning less over traditional home lines.  

    Despite disappointing fixed line business, mobile and internet divisions are booming with Telstra winning back previous losses to Optus and Vodafone, says Deutsche Bank analyst Andrew Anagnostellis. 

    “Mobile is looking good for Telstra and it should look good because they have sunk a lot of money into it. That’s important because part of Telstra’s $1bn strategy was to get out there and grow market share. And they look like they have achieved that to some extent,” he told The Australian.

    Revenues also look set to fall 0.7 per cent to $12.2bn. 

    However, many analysts are keen to find out if their ‘Project New’, its  $1 billion bid to improve customer service and lure clients back into the Telstra fold will pay dividends, given its massive cost.

     

    “Telstra has lost customers over the past year and in response to the erosion of our customer base we saw two strategic options,” the company said last year. 

    “We could focus on maximising cash in the short-term, cut costs and continue to lose market share, or take a long-term view by investing in customer service, simplifying the business and competing effectively to retain and acquire customers.” 

    Analysts also predict the Telco will again declare a fully franked interim dividend of 14c per share, in line with management objectives of a 28c dividend over a two year interm.

    However, thats not all going on at the communications house.

    This week may see the Telco finally confirm its $11 billion deal with
    the NBN, according to the Australian Financial Review. 

    The
    Telco, due to announce its half year financial results this week, may
    also outline its honourable intentions with the National Broadband
    network, which needs its shareholder approval before it can get the go
    ahead. 

     

    Chiefs from both NBN and Telstra, Mike Quigley and David
    Thodey were reported to have held a productive meeting last week
    helping to finalise details of the selloff of the Telco’s copper fibre
    network in return for broadband contracts and a large pay out.
               
    Telstra,
    who are to present shareholders with the NBN deal for approval this
    June, are at risk of delaying the deal as bureaucracy gets in the way, analysts at
    Goldman Sachs warned last week.

    Oops: Expedia Promotes Fallen NZ City

    Travel giant Expedia tries to drum up travel trips to NZ, while an earthquake measuring 6.5 on the Richter scale devastates its second largest city of Christchurch.


    Click to enlarge

    And if that wasn’t enough the Internet company also went one further by using an image of the City’s cathedral, now at the centre of the earthquake as a promo shot.

    Several people lost their lives at the site and many more are said to be missing.

    The e-mail promo was sent to its Australian customers this morning from UK based marketing division although the disaster struck before lunchtime yesterday. 

    However, Expedia have blamed timing, saying “these promotional emails are built and deployed from our team in London and this one was deployed before the earthquake hit. ”

     “Expedia sincerely apologises for the unfortunate timing of this communication, which was removed from our website as soon as we became aware of the contents. 

    We are working with Expedia customers who are planning to travel to or from the affected area to make alternative travel arrangements.,” said the Washington based travel co.       

     

    75 are now confirmed dead and over 1,000 people are unaccounted for.

    Apple Killing Rivals As iTunes Gets Greedy?

    US authorities begin examining Apple iTunes new business arrangement as content providers cry foul.Steve Jobs’ company, which is taking a 30 percent cut from all non-Apple content sold through its music store has set alarm bells off in official circles who suspect anti-competitive practices are being pedalled by the tech giant. 

    The US Justice Department as well as the Federal Trade Commission, who is responsible for investigations into unfair trading practices, have not yet acted on the case but are carefully examining the situation as are the European Commission, according to The Australian. 

    Media companies wishing to sell their music, movies, games and e-books applications through the  eponymous iPhone, iPad iPod or Mac PC are forced to go through the Apple payment system, where they take one third of the sale price.

    These new rules makes doing business through iTunes and now its other publication subscription services on its iPad and iPhone an unprofitable game for outsiders. 

    In addition, Apple makes it almost impossible for customers to make purchases externally, forbidding all outside links to other retailers.

    And if that isn’t enough it also prevents other companies from building relationships and gaining personal information on their customers and makes it easier for music lovers to purchase from its iTunes Store if they have previously made a purchase as billing details are already stored in their system. 

     

    The tech powerhouse don’t allow the retailers to retain customer information but keep it on file for their own marketing department’s use. 

    Complaints from music companies are fierce and most providers are deeply unhappy with the new regime.

     “The costs don’t leave room for a sensible business model,” says Jon Irwin, of Rhapsody international who already sells content through the system. 

    “The rate is so obviously anti-competitive it will never survive in Europe,” states Axel Dauchez, president of Deezer, another digital music provider. 

    This also comes as Apple announce a new subscription service for publishers also, which will allow users to make purchases of magazines or newspapers on a weekly or monthly basis, which the company says will give publishers a revenue boost, given the flexibility of the business model.

    But the same business arrangements including the 30 per cent cut apply as with the iTunes model. 

    However, Steve Jobs denies any wrongdoing in the new arrangements.

     

    “We believe this innovative subscription service will provide publishers with a brand new opportunities to expand digital access to their content onto the iPad, iPod touch and iPhone, delighting both new and existing subscribers,” Jobs said in a statement.

    Huawei Ascend: ‘World’s Thinnest’ Phone

    It’s the Kate Moss of smartphones – the world’s slimmest ever device has just been unleashed by Huawei at CES.

    The slim yet potent 6.68mm device on an highly impressive 4.3″ 960×540 Super AOLED qHD display, Ascend P1 S runs Google Ice Cream Sandwich 4.0 and sports a 1.5GHz dual-core Texas Instruments OMAP 460 Cortex-A9 processor and SGX 4460 graphics engine for the gamers amongst us.

    And thin the P1 S certainly is – leaving Motorola’s 4.3″ Razr with 7.1mm depth, iPhone 4S’s 9.3mm and Samsung’s Galaxy S 8.9mm smartphones look frumpy by comparision – and protected by Corning Gorilla Glass.


    Click to enlarge

    Another slightly thicker model, the 7.79 mm Ascend P1 also packs similar specs to its slimmer sister – and other best-in-class mutual specs include Dolby Mobile 3.0 Plus 5.1 surround sound, front 1.3MP and rear 8 MP cameras with 1080p HD video for Skype calls, which also come with a flurry of cool party tricks including video editing and face distortion tools similar to Apple Front Row, according to The Register.

    Bluetooth, 802.11b/g/n Wi-Fi, HDMI to connect up to a TV also come as standard.

    “It’s very convenient, very comfortable in your hand,” Huawei chairman Richard Yu told CES press audience in Las Vegas yesterday on the eve of the event which kicked off today US time in Las Vegas.

    “The Ascend P1 S demonstrates our ongoing commitment to innovating high quality devices that utilize the latest hardware and software technologies.”  

    And, thanks to the top spec processor, the high end Huawei’s will be “the fastest in their class,” says Yu.

    In addition, the Ascends’ also promise longer battery life – up to 30% longer – thanks to 1670mAh, 1800mAh batteries.

    The new smarties also have a maximum of 8GB of storage when coupled with a microSD card but has 4GB standard and 1GB RAM.

    Yu also cited a price of around US$400 although did confirm the sleek model would be available Down Under probably in April after it hits Europe in March.

    No word on local carriers either although a Huawei Australia spokesperson told SmartHouse: “We’re currently in talks with Australian operators but a release date hasn’t been confirmed yet.”

     

    And like Kate Moss, Ascend likes to be fashionable and comes in funky cherry-blossom pink  colour as well as bog standard black and white.

    No word yet how the Ascend feels in the palm of a hand but look out for hands-on reports later this week.

    Panasonic MD Talks Appliances, TVs & The BIG Issue

    As Panasonic invades the white goods market, Channel News caught up with MD Steve Rust to see how its going.


    Click to enlarge

    Panasonic is now a fully fledged white goods brand in OZ, flogging everything from bread makers, irons and rice cookers, to washing machines and 8 smart fridges.

    “Demand has been great to date” says Steve Rust, Managing Director, Panasonic Australia, but “it’s early days.”

    “We’ve sold out of inventory and there’s been good feedback from market” citing retailer Harvey Norman, whom Rust says is “selling well” on Pana’s new gear.

    Panasonic now has over 50 white goods models on the Aussie market. One out of every two Pana products sold worldwide is now white goods and outsells its Audio Visual category .

    And  the giant hopes to repeat the trend locally.

    So, what prompted the big change to irons and washing machines for a company best known for TVs and Blu-ray?

    “We had an imbalance in the business… there was too much reliance on AV and CE business and as we know its a tough business to be in…with very rapid price erosion and no growth in the past 2 to 3 years,” says Rust.

    This ‘imbalance’ forced Panasonic’s management team to take a “prudent” approach to the market at hand.

    It now has three key pillars to its business in OZ – AV, Appliances and Communication solutions for business, which is also doing nicely.

    Speaking of TVs, how’s that side of Pana’s business going?

    “Demand hasn’t grown as such but its greater than expected, however, we can’t get enough TVs to sell,” Rust says, citing issues on the supply-side from Japan.

     

    “We have to order three months in advance..but have more coming,” he adds.  This supply issue was one AV specialist Len Wallis cited last week in an interview with CN, saying he was unable to meet the huge demand for Pana large screens.

    “The market has settled this year and, its not as furious in terms of price erosion and demand for TV’s is sitting at around 3 million units per year,” says Rust.

    Despite the entry into appliances, Panasonic is still “very strong” in AV, and the DVD recorder market is “good for us”, which may have been fuelled by the Olympics. Pana’s home theatre market is also “chugging along quite well.”

    “The biggest issue in the AV market right now is the expanding amount of IP content and the seamless integration between IT and consumer electronics,” says Rust.

    “The amount of IP content is expanding rapidly and is now provided in a way that is highly accessible to consumers.”

    Streaming services such as Spotify, JB HiFi Now, QuickFlix and others means the days of downloading content from a PC or using just iTunes are well over.

    On the appliance side, power consumtion is also becoming more and more important as electricity prices go up, but adds Pansonic’s Econavi power saving technology inbuilt into its appliances including washing machines deals with this issue very well.

    Panasonic Australia also launched a slew of cameras last week – everything from a basic compact LX7 through to high end mirrorless cameras and Rust was “very pleased with the launch” and the response so far. 

    However, “there has been a general drop in demand for cameras due to the invasion of smartphones like iPhones, especially at the entry level.”

    In addition, there is now more and more competition from online operators overseas as well as competition from the high end.

    Online channels are “growing rapidly,” says Rust, adding its not just foreign e-tailers in play – there’s is a lot of competition locally between the likes of Appliances Online and JB Hi-Fi.

    But it doesn’t mean the end of bricks and mortar just yet, and Rust says he is “confident they’ll always be room for the instore experience.”

    “Some consumers love the convenience of online but there will always be plenty who want to go instore for the product experience – to get the look and feel, talk to the storeperson and so on.”

    However, Panasonic’s MD questions the future success of international e-tailers, as issues like after-sales services issues come to the fore.

     

    “There are some questions about service in Australia for a camera that bought, say, in the US,” and adds “consumers may not be comfortable buying international e-tailers in the future.”

    “We are working with online partners including Appliances Online and are keeping an eye on other pure online retailers,” says Rust, adding Pana is being selective on choosing retail partners.

    Afer sales service is an issue the brand is particularly concerned with and “we want consumers to have a good experience when they buy a product and ensure retailers have good return capabilities.”

    However, he admits bricks and mortar retail in the future may be a bit different from today, and predicts there definitely more changes to come.

    Hello, You’re Fired. Goodbye. Yahoo!

    Tele-fired: we’ve heard of being dumped on a Post-it, but fired over the phone from one of the biggest tech companies in the world?


    Click to enlarge

    This is precisely what happened to Carol Bartz, Yahoo CEO, who was ousted from the top seat by Chairman Roy Bostock by telephone yesterday. 

    “I am very sad to tell you that I’ve just been fired over the phone by Yahoo’s chairman of the board,” Bartz, told staff in a memo send from her iPad. 
    “It has been my pleasure to work with all of you and I wish you only the best going forward.” 
    Carol Bartz replaced Jerry Yang as CEO in January 2009, was given the task of turning around the former stalwart of the Internet, after it managed to dodge a $47.5 billion takeover attempt by Microsoft. 
    Yahoo! has suffered hard losses at the hands of Google, although has a decent business in Australia, thanks to its partnership with the Seven Network, reported global earnings below estimates in its most recent financials in July. 
    Chief Financial Officer, Tim Morse, will take over the top role for the interim and is actively looking for a permanent replacement, the company said in a press release. 
    Yahoo! also confirmed Bartz has been “removed” from her post. 
    Investors reacted well to the news with shares rising as much as 8.4 percent, according to Bloomberg. 
    Analysts also welcomed the move, but are now citing a possible sale of the web portal to a major media conglomerate like News international. 
    “After all of the drama of the Bartz administration, we think the Yahoo! board of directors may be more receptive to a deal now than it has been in the past,” said Jordan Rohan, analyst at Stifel Nicolaus & Co. 
     

    And Rohan is also citing a major management and strategy overhaul, at the very least. 

    Chairman Bostock declined to comment on the tele-firing but did say:
    “On behalf of the entire Board, I want to thank Carol for her service to Yahoo! during a critical time of transition in the Company’s history, and against a very challenging macro-economic backdrop.”
    “We have talented teams and tremendous resources behind them and intend to return the Company to a path of robust growth and industry-leading innovation.


    Cut Prices, New ‘Centre’: ‘Price Gouger’ Accused Adobe Desperate For OZ Love?

    Slashing prices, “amazing” Sydney demo centre….Adobe is looking for some Aussie love.

    As Adobe gets set to be grilled under the IT pricing inquiry, it is opening new offices and ‘demo centre’ in Sydney tomorrow, supported by communications Minister Stephen Conroy.

    As well as rapidly cutting the price of some of its software today, ahead of a parliamentary grilling next month, Adobe also announced the opening new offices and ‘demonstration facility’ in Sydney tomorrow, unveiled by Adobe’s CEO Shantanu Narayen, flanked by Senator Stephen Conroy and NSW Premier Barry O’Farrell. 

    “It’s an amazing demo room, looks like a cinema almost with a great digital media experience – you will love it,” an Adobe spokesperson told SmartHouse.

    You can’t buy Adobe products from the demo facility located at Sydney CBD at 201 Sussex Street, however.

    The media invite was only sent out at short notice this afternoon for an event taking place at 10am tomorrow, as Adobe also slashed prices of Creative Cloud by 20% today.

    Earlier this week, it was summoned by the IT pricing enquiry to appear before it to explain the massive price disparities between US and Aussie pricing on Adobe products.

    Read: Adobe Slash AU$ Prices... Apple + Microsoft To Follow?

    Incidentally, Conroy was the minister who signed off on the IT pricing inquiry, which this week summoned Adobe, Apple and Microsoft to answer before the parliamentary inquiry in Canberra on March 22 next.

    However, a spokesperson for the minister denied there was any link between the two events, saying they are “very separate” and the IT pricing inquiry is a parliamentary matter, not a ministerial one.

    Adobe’s CEO Shantanu Narayen will be there tommorrow, perhaps to butter up the pollies ahead of the showdown before the inquiry next month, where Apple and Microsoft execs will also face the stand, to explain the massive price disparities between US and Aussie pricing on gear like Adobe products, iPads and Windows software.

    Retravision Leakage Continues As Winning Nab Qld Store

    Retravision leakage continues as Winning Group snaps up a Retravision store in Indooroopilly, Queensland.


    Click to enlarge

    The Ron Handley owned Retravision store based in Brisbane will now be run under the Winning Appliances name, marking the group’s second QLD showroom.

    Betta group already snapped up 40 stores from Retravision Northern group, Southern and West after 104 stores from Southern group went bust earlier this year, believed to have debts in the tens of millions.

    General Manager of Ron Handley Retravision, Mel Spiteri, will retain his role, with most employees are expected to join the Winning Group.

    “Our acquisition of Ron Handley Retravision expands our presence in the Queensland market to two showrooms, joining our showroom in Fortitude Valley which opened a year ago,” John Winning, CEO of the Winning Group, said.

    Winning’s latest investment  – its second in the space of a week – represents a “strategic opportunity” to expand its business in Queensland, which is currently experiencing strong growth, he added.

    “The Indooroopilly showroom is in a prime location and with Mel Spiteri at the helm, it has achieved a high level of customer service, which we are keen to maintain.”

    “We are delighted to have Mel Spiteri’s experience to assist in leading the team and growing business in the local area,” said Mr Winning.

    This marks the second acquisition by Winning in less than a week – it also announced the purchase of Power Buys online retail and McKnights corporate business just days ago.

    The Winning group includes Winning Appliances, Appliances Online, Big Brown Box and Handy Crew.

    Apple Deny Apps ‘Bug’ Threat

    Cupertino insists apps bug is fixed, denying it affected that many users in the first place.


    Click to enlarge

    Apple’s Apps Store ran into a number of difficulties last week.

    Malware which pinched a user’s contacts was discovered in an Apple (and Google) app last week by Kaspersky Labs, while a separate issue involving popular apps like Angry Birds to crash was also reported to have affected 20,000 iOS users.

    The ‘suspicious’ software discovered on the ‘Find and Call’ app – was found to be a ‘Trojan’ that uploads phonebook contacts to a remote server and then proceeds to use it for SMS spam, probably trying to con users out of cash.

    The malware was also found to affect Google’s Android Play store, although security experts noted it was the first case of malware on Apple’s Apps store in five years since its opening.

    Although the Find and Call “malware [is] not that ‘cybercriminalistic’…we’re sure that there must be strict and quick response to such incidents. Period,” writes Kaspersky Labs’ Denis Maslennikov.

    Reports also indicate Mac developer Marco Arment discovered a separate ‘bug’ on over 100 apps in Apple’s Apps Store where iOS customers purchased apps, which proceeded to crash even when deleted and reinstalled.

    However, it only affected customers in some regions and occurred between July 3-5 last, noted Arment, who branded it a “serious issue,” calling on Apple to “please fix this” .

    Other apps affected included The Huffington Post, Yahoo! Search and iDesign (114 in all).

    These crash and burn apps will also cause ire among developers as “they’ll leave you a lot of angry 1-star reviews,” he adds, referring to angry app users who keep trying to download apps that fail, causing them to think it’s unstable and rate it poorly.

     Appledenied the apps caused widespread disruption, insisting the malware affected a “small number” of users only and said the issue has now been rectified on July 06.

     

    “We had a temporary issue that began yesterday with a server that generated DRM code for some apps being downloaded, it affected a small number of users.

    “The issue has been rectified and we don’t expect it to occur again. Users who experienced an issue launching an app caused by this server bug can delete the affected app and re-download it.”

    However, Arment disputes this estimation by Apple, insisting “probably” 20,000 were affected by the bug, noting Apple has triggered a reupdate on the affected apps, rather than deleting them as this would cause a user’s existing app to disappear.