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

    Smart Office

    Clive Peeters Open To Take Over Offers

    Clive Peeters CEO Greg Smith who today reported a 90% decline in profits has said that he is open to takeover offers or a major new investor. He has also said that the board is currently considering several incomplete proposals from competitors to buy out the Victorian based consumer electronics Company.

    Clive Peeters CEO Greg Smith who today reported a 90% decline in profits has said that he is open to takeover offers or a major new investor. He has also said that the board is currently considering several incomplete proposals from competitors to buy out the Victorian based consumer electronics Company.

    Speaking to ChannelNews today Smith said that he believed that many Companies will between now and July 1 when new dismissal laws come into effect in Australia lay off thousands of workers and that appliance and consumer electronic sales will not pick up till the September October period.

    He said “60% of our business is appliances and this side of our business is down over 12% while our consumer electronics business is up over 5%”.

    On the question of New South Wales he said that the Clive Peeters group was suffering because of a lack of stores and that the Company has plans for 12 new stores in that State.

    He said “We are pleased that there is continued improvement coming through in NSW despite the very depressed conditions in that State”.

    Sales in H1 in NSW 2009 fell 7.6% on the corresponding period of the previous year, the best performance of our eastern states operations.  Our operating costs in Sydney were managed very carefully over the period and the final result was $1.6 million net operating loss after tax for H1 2009.  This compared to the H2 2008 Sydney loss of $1.8 million after tax, and to the H1 2008 Sydney loss of $2.6m after tax, so we are encouraged by this trend.

    “To grow we have to invest in NSW and this is a top priority for the board going forward”. Said Smith.

    On the issue of Dick Smith Vs JB Hi Fi he said “I agree with the sentiment that Harvey Norman could get hurt if there is increased competition between the Woolworths owned Dick Smith group who do have money and JB Hi Fi. I also agree with the sentiment that Dick Smith stores are traditionally small and they do not have the same brand recognition as JB Hi Fi. For example JB Hi Fi shift a lot of small cheap stock similar to Dick Smith for example our average sale is $800 vs $80 for JB Hi Fi”. 

    Greg Smith added “with sales under significant pressure this caused increased competition and a sharp fall in gross margins over H1 2009 – the Company’s first margin decline in over 15 years, which says a lot about how challenging this retail environment is.

    Greg Smith stated “these times demand strict management of inventories and cash flows, and we are doing well in these two areas.  Capital expenditure is under a tight hold, and no new stores are committed to or planned for calendar year 2009.

    However on a positive note our pilots for kitchen and bathroom renovations (Moorabbin and Thomastown) and for a range of new technology, software and gaming product (Moorabbin) have both been launched in recent months and are showing promising early results.  We expect these product and services innovations to represent a platform for like stores sales growth as we roll them out to other stores when the retail cycle improves.

    Toshiba Expose Worlds Fastest Gaming Machine

    The world’s fastest gaming machine is set to be rolled out in Australia. It is also the most powerful notebook ever built by Toshiba.

    It is expected that the bright rouge red 17″ Qosmio X305 will go on sale mid August with a retail price slightly in excess of $2,000. The machine which was shown for the first time in Australia at the Toshiba mobile exchange conference in Sydney has Toshiba’s slick looking fiery moulded finish which is set to be seen on other Toshiba notebooks as well as Toshiba LCD TV’s.

    Click to enlarge

    A 1GB NVIDIA GeForce 9700M GTS discrete card powers the graphics and the CPU is an Intel Core 2 Duo P7350 processor.
    Other features of the system include support for DDR3 1066MHz RAM, a 17.1-inch LCD, and 200GB of storage. The keyboard of the system is a full size unit with a number pad as well. The sound system uses four Harman Kardon stereo speakers with a built-in subwoofer. Buyers will be able to choose to use Windows Vista 32-bit or 64-bit at the first boot.


    General Manager of Toshiba Information Systems Mark Whittard said “We are looking forward to the launch of this beast. It is the fastest notebook every built by Toshiba and we are confident that it will appeal to gamers”.
    Toshiba have also said that they are exploring new retail outlets for their gaming machine including the4 likes of EB Games. They have also said that they have held discussions with JB Hi Fi who are one of the biggest sellers of gaming software for PC’s and gaming consoles.


    Click to enlarge

    The Car You Can’t Crash Made By Volvo

    First came ABS braking, then came active suspension, then came the onboard computer that was able to adjust a car as it started to slide. Now we have the car you can’t crash, thanks to Volvo.

    That sickening – not to mention painful – feeling as your car crunches into a vehicle in front looks like becoming just an expensive memory for drivers.

    Volvo has come up with a crash-proof family car which will go on sale in the autumn. Its secret is a laser-guidance system to spot vehicles in front that are too close or stopping suddenly. When it does, the Volvo will stop of its own accord to avoid a smash.

    Click to enlarge

    Sci-fi reality: The crash-proof car spots dawdling vehicles using a laser-guidance system installed in the windscreen The CitySafety system, which kicks in at speeds of up to 20klm and is designed for urban driving, has the potential to prevent half of all rear-end collisions, said Volvo.

    A laser sensor built into the windscreen reacts to traffic in front that is either stationary or moving in the same direction. It scans up to six yards ahead and, sensing the difference in speed between it and a vehicle in front, it makes 50 calculations a second to determine the braking force needed to avoid crashing.

     

    If the driver fails to slow, the system brakes automatically and disables the accelerator. The system will be standard in the XC60 model Volvo. But Jonas Ekmark, of Volvo, said: “It is important to stress that CitySafety does not relieve the driver of the responsibility from maintaining a safe distance.”

    Safety experts say this and similar technology being developed by other makers will help save more than 125,000 painful and costly whiplash injuries alone each year.

    Rear-end collisions make up 29 per cent of all reported car accidents. In more than half, the driver does not brake at all. And 90 per cent of all such collisions are partly due to distracted drivers.

    Three-quarters of all collisions happen at speeds up to 25 klh. Volvo said that if the relative speed difference between two vehicles was below 10mph the system can help avoid a collision entirely.

    “Between 10mph and 20mph, the focus is on reducing speed as much as possible before impact,” said Volvo. At higher speeds, including on motorways, a separate “adaptive cruise control” system keeps the car safe from traffic in front by braking and accelerating as necessary.

    Volvo, Mercedes and Honda will be demonstrating their anti-collision technology at a driver training centrein the UK this week.. A spokesman for the centre said: “It sounds like sci-fi fantasy – cars that can’t crash. But the fictional notion is about to become reality.”

    Three Tech PR Companies Facing Problems As BlueFreeway Freefalls

    The Company that owns Spin Communications, Max Australia and Spectrum Communications all PR Companies that handle major technology clients has reported a $4 million dollar loss with directors now admitting that the Company Bluefreeway is up for sale.


    Shares in the Holding Company have crashed over 40% on news the group recorded losses of $4.048 million in the first half of the current financial year. Currently suspended the Company that has Greg Daniels the former CEO of Clemenger on their board is desperately looking for a white knight.
    Blufreeway claims that it has entered into exclusive due diligence with a potential suitor. It has also been revealed that the Company is looking to sell off recently acquired assets. Among the technology PR clients who could be affected if Bluefreeway does engage in a fire sale of assets are Telstra Bigpond,  Acer, Blackberry, iBurst, Gizmo, Intel, pba (Personal Broadband Australia), MessageLabs, Orbi, and Blur-ray Disc.
    According to ADNews A spokesperson for Bluefreeway confirmed “a number of parties” had expressed interest in acquiring the company over the past few weeks, with shares in Bluefreeway languishing well below its listing price despite the group more than doubling in size over the past 16 months.

     

    Bluefreeway co-founder and interim executive chairman Greg Daniel said the company had retained Merrill Lynch and Bluestone Capital to assess the offers.
    Bluefreeway would not provide a timeline on the due diligence currently under way, nor details of any of the group’s suitors.
    “While this approach is indicative and non-binding, and may not translate into an offer, the board felt it was necessary to notify shareholders. The Bluefreeway board will act in the best interests of shareholders and keep the market fully informed,” said Daniel.
    Bluefreeway posted first half losses of $4.048 million late on Friday (29 February) while the company’s shares were in a trading halt pending the release of today’s announcement. Within hours of the trading halt lifting today, Bluefreeway’s shares had plummeted over 40% to $0.35.

    Bluefreeway management was at pains to point out the company’s recent poor performance was not a reflection of the profitability and growth of the group’s 25 portfolio companies. In the six months to 31 December 2007, Bluefreeway recorded revenue of $35.3 million and gross profit of $23.8 million. These profits, however, were eaten away by blown out corporate costs.
    “This disappointing and unacceptable result can largely be put down to a high level of corporate spending, accompanied by a lack of corporate sales,” said Daniels.

    Between October and December 2007, Bluefreeway’s previous management team, working under ex-CEO Richard Webb, employed 28 additional executives across six countries.
    “When the board became fully aware of these unsustainable corporate costs in December, we engaged PricewaterhouseCoopers to perform a review. The findings of this review, the extent of the corporate costs and the speed at which they were accrued in late 2007, confirms that the board’s decision to change management and refocus the company was correct.”
    Daniel said the Blu portal would not be scrapped as part of the new management’s corporate cost cutting exercise, although future expansion of the portal would take place from a sustainable cost base and in an evolutionary fashion.
    “As a result of the corrective action taken by the board, coupled with a growth in sector, we believe that our earnings for the next financial year will return to a more acceptable level,” he said.

    http://www.adnews.com.au/news.cfm?NewsID=4364&alpha=17000&beta=46539

    Apple May Buy Palm

    Apple Computer, who are concerned over the impact of mobile phones on the sale of iPods, are according to insiders considering the purchase of the troubled Palm Group makers of the Treo mobile phone.

    Speculation that Apple plans to buy handheld maker Palm has been revived by a call from two leading Palm investors for the company to be put up for sale, according to the local paper of both companies. Mike Nelson, who owns eight per cent of Palm shares, argued that the company is poorly equipped to dominate the market for smartphones which are beginning to eat into sales of traditional PDAs, reports Siliconvalley.com , online edition of the San Jose Mercury.

    The drift from PDAs to smartphones is borne out today by a report from analysts IDG. Palm has sold one million phone-enabled Treos and its stock has nearly doubled in value over the past year. But Nelson is reported to have told the Palm board that competitors are developing products quickly and could afford to sacrifice profits to gain market penetration.

    Another shareholder, with five per cent of Palm shares, also urged a sale of the company late last year. The fact that Apple has been named as a possible buyer may seem strange to those who recall that one of the most controversial acts of CEO Steve Jobs was to kill off the pen-driven Apple Newton, a pre-cursor of the Palm Pilot, when he returned to the company after a 10-year absence in 1996. Yet the two companies are closely linked. They are near neighbours and several early Palm employees, including co-founder and former company president Donna Dubinsky, previously worked with Apple.

    Palm, at least in its early days, also enjoyed the kind of anything-but-Microsoft fan base that has long sustained Apple. Jobs tried to buy the company in the late nineties, according to the Mercury.
    Neither Apple nor Palm has given any sign that there is any basis for the renewed speculation but there are obvious fits between the two companies.

    Apple’s Ipod boom can hardly be sustained unless it can head off competition from PDAs and smartphones that can pack music players along with a host a other functions. Palm itself was slow off the mark in adding tricky telephony technology to its products and Apple would have a hard time starting from scratch in the market.

    Also, for all their vaunted style, the latest Apple notebooks look like antiques beside the latest pen-driven Tablet PCs.

    The company will sooner or later be forced to offer a pen interface, and could benefit from Palm expertise in the area – especially as tablets are getting smaller, and may eventually supersede the PDA.


     

    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.

    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)”.

    Samsung Revenues Surge As Profits Hit $24M

    Samsung Australia, who five years ago were struggling to get traction in the Australian market is now outperforming most other consumer electronics Companies including LG, Apple, Google and Sony.

    According to documents lodged with the Australian Companies and Securities Commission, Samsung Australia has seen revenues jump from $1.29 Billion in 2008, to $1.6 Billion in 2009. 
    Profits for the local subsidiary climbed to $24.2 Million in 2009 from $16.10 Million in 2009. Advertising and marketing budgets went from $53M to $60M while staff costs went from $25M to $29M. In comparison Google spends $81 Million on staff costs despite only have $110M in revenues in Australia.
    In comparison Apple who has bragged about the success of their iPhone and iPad sales was only able to deliver a profit of $2.5 Million on similar revenues to Samsung.
    LG Australia in comparison was only able to deliver a profit of $13K on revenues of $968 Million during the same period.
    Sony, who report their financial results in July based on a Japanese year end of April is tipped to report a decline profits and sales after last year reporting record sales of $924 Million and profits of $34.59 Million.
    According to Samsung Australia executives the Company is witnessing record growth across all divisions, including their recently restructured IT division which last year appointed former BenQ executive Phillip Newton to head the division.
    In the AV market Samsung has grown 27% since May 2009, when the overall market has only grown 3% the Korean Company claims. Overall Samsung now has 20% of the total AV market.
     According to GfK data, Samsung has achieved the highest level of combined value sales across its four biggest AV categories – flat panel TV, digital camera, portable media player and DVD/Blu-ray Player market – from May 2009 through April 2010.

     
    Head of Corporate Marketing for Samsung, Lambro Skropidis, said “It’s exciting to see the Samsung brand enjoying so much consumer support. Our tracking data shows that consumer awareness and preference for our brand has been continuing to build from year to year. The ultimate expression of consumer support is seeing preference translate into higher levels of sales at the store level.”
    Several consumer electronics Companies are suspected of deliberately engaging in tax minimisation through the use of offshore subsidiaries in tax havens. Google for example has a service agreement with Google Ireland for the provision of sales and marketing advice. 
    According to sources in the Australian Tax Office, some International consumer electronics Companies re set to be investigated for transfer pricing after delivering extremely low profits.
    In the past several IT Companies have been prosecuted for transfer pricing practises. This often involves goods being sold to a local subsidiary at one price, often higher or equal to what it is being sold in Australia. This allows a local subsidiary to transfer profits out to an International Company located in a tax haven or low tax Country.
    The Australian Tax Office said that the purpose of Australia’s transfer pricing rules is to counter the underpayment of Australian tax by businesses that are also International.
    They claim that pricing for international dealings between related parties should reflect a fair return for the activities carried out in Australia, the Australian assets used (whether sold, lent or licensed), and the risks assumed in carrying out these activities.
    They claim that transfer pricing is often referred to as ‘international profit shifting’.

    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.