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 56 of 116

    Smart Office

    Asus Infinity Tab: Full-HD …And Beyond

    Infinity HD and beyond: Asus launch new Transformer – the first full HD tab.


    Click to enlarge

    The 10.1″ tablet boasts same viewing experience as a large screen TV with 1920 _ 1200 resolution Full High Definition Super IPS+ display – the first Android tab to do so.

    New iPad released earlier this year has 1080p HD video and better res of 2048 x 1536 on its 9.7″ Retina display, but Asus Infinity is the world first Android to have full HD most other ‘Droid tabs having around 1280×800 res.

    Asus Transformer Infinity boasts full 1080p HD video recording and playback meaning all your shots will be top notch quality.

    And for multimedia fans, it features SonicMaster audio technology for excellent speaker quality and large resonance chambers and runs Android Ice Cream Sandwich 4.0 OS for all the usual Google apps inbuilt.

    Infinity will be upgraded to Android’s new Jelly Bean when it is released.

    The trick with Asus Transformer tablets are they comes with a removeable mobile dock with a keyboard, meaning it literally transforms into a notebook device instantly, so is good for work use also.

    Asus new Transformer also has a super-bright 600nits Super IPS+ mode good for outdoor use and the fastest NVIDIA Tegra 3 Quad-core CPU running at 1.6 GHz (WiFi model).

    The 3G version comes with Qualcomm Snapdragon Dual-core 1.5Ghz CPU. The processor also easy on power and Infinity promises 14 hours battery life (attached to the dock on 720p playback and power saving mode) and 9 hours without the dock.

    Asus has also kitted the Infinity out with 2nd generation Corning Gorilla Glass 2 for better damage resistance and connectivity wise has USB drive, MicroSD card and 8GB of ASUS WebStorage for life.

     

    The ultra-slim and light Transformer Pad Infinity is 8.5mm thin and weighs 598g.

    Other specs include a full QWERTY keyboard and touchpad, 8MP rear auto-focus camera with LED flash and 2MP front camera allows for video-chats.

    However, Full HD doesn’t come cheap and will set you back just under $1000 for 64GB version although a cheaper model is set to come out later this year for around $799. 

    He Is Out: HP Boss Booted.. In Comes eBay Meg

    Its official, Leo Apotheker has been given the sack and replaced with ex eBay boss, whom he originally hired as a Director.


    Click to enlarge

    HP board confirmed the firing yesterday, saying it was “fortune” to have someone of Whitman’s calibre and “track record” to lead the lost tech giant at a “critical moment”- a clear dig to Apotheker who had been in the top job less than a year.

    “We are fortunate to have someone of Meg Whitman’s calibre and experience step up to lead HP,” Ray Lane HP’s new executive chairman declared.

    “We are at a critical moment and we need renewed leadership to successfully implement our strategy and take advantage of the market opportunities ahead.”

    “Meg is a technology visionary with a proven track record of execution. She is a strong communicator who is customer focused with deep leadership capabilities,” he added.

    This is the Hewlett Packard board third ousting in as many years. Carly Fiorina and sexual harassment accused Mark Hurd were previous victims.
     
    Apotheker, the former head of SAP was ousted due to a ‘lack of leadership and poor execution’ according to HP sources although the No.1 PC maker is still sticking by the now ex-boss’ decision to rid itself of its hardware business.

    Whitman joined the HP board earlier this year under the direction of Apotheker, who saw through three consecutive quarters with a lowered financial outlook, falling share price – over 45% this year alone – and most recently announced HP was to spin off its still profitable PC and notebook business.

     

    “As a member of HP’s board of directors for the past eight months, Meg has a solid understanding of our products and markets.”

    Whitman, a former Republican party candidate who steered internet giant eBay to major success until 2008 said she was “excited” to lead a company the world needs.

    “I am honoured and excited to lead HP. I believe HP matters – it matters to Silicon Valley, California, the country and the world.”

    But analysts aren’t happy with the move at the top and say it will only make an already shaky company into an even riskier company to do business with.

    “HP is flailing, causing more uncertainty and increasing the risk of doing business with it,” Carter Lusher, Ovum analyst has warned.

    “Whether or not the rumor is correct or not, the damage has already been done” and “only reinforces that HP is a company that is in severe disarray.”

    However, it may not be all bad and Whitman’s experience although lacking in the hardware department, could prove beneficial for it’s fast growing services business.

    “Whitman lacks experience running a global enterprise IT vendor, but she does have experience as an enterprise IT customer (as CEO of EBay), and understands the value of consulting services (having started her career at Bain).”  say Jens Butler and John Madden, Ovum Services analysts.

     

    Read Apotheker Ousting: HP ‘Flailing’, As Future Hangs In Balance Here

    HP shares slumped down 4.9% on Wall Street close yesterday, to $US22.80 amid a broader market sell off.

    Its Bad: Sony Hack Jacko Nicked, Security SCREWED

    Sony’s latest Michael Jackson hack scandal spells serious trouble for the already troubled giant, as experts warn attacks are worsening.


    Sony latest hacking revelation is bad.

    Sony Music’s entire Michael Jackson back catalogue collection, worth more than $250 million, was stolen by “Internet hackers” last year, it emerged yesterday.

    The hackers took more than 50,000 music files, most of which were by the late pop singer by compromising Sony’s security systems.

    High profile artists like Jimi Hendrix, Paul Simon, Foo Fighters and Avril Lavigne were also affected.

    Sources say there was “a degree of sophistication” associated with the latest attack, according to The Sun.

    However, Sony refused to say how many tracks or artists were affected. 

    This latest hacking revelation comes despite the giant promising “all” their sites had been secured following a major hack attack on their PlayStation network, which took the Japanese giant weeks to inform its 77 million PSN users, whose accounts and personal data may have been stolen.

    And it appears the attack on the Jackson files occurred not long after this but has not been revealed to the public, until now.

    Shortly after Jackson’s death, the singer’s estate signed their biggest recording deal in history worth $250m with Sony Music, giving it the rights to sell his whole back catalogue as well as unreleased tracks.

    Two men who were arrested in May last year in the UK appeared in court last week accused of offences in relation to the Sony hack.

    This latest revelation does not bode well for Sony and is having a major negative impact on its business, say web security experts.

    “Cyber crime has certainly reached its tipping point around the world,” admits Ty Miller, Chief Technology Officer, Pure Hacking.

    “As is the case with Sony and its ongoing issues, these attacks are making a very significant commercial impact.”

    “It is no longer optional for organisations to ignore security requirements and prepare their organisation for a new operating environment where they may be under constant attack,” Miller warns.

    So what does this mean for web security as more and more big names are being attacked? Internet security experts McAfee Labs predict the “true” Anonymous hacking group will either reinvent itself, or die out while others are also predicting hacktivism on companies, public figures and politicians is on the rise.

     

    Organisations need to understand the risk profile that they have by regularly performing penetration testing, which allows them to mitigate their vulnerabilities before a security incident occurs, says Miller.

    Companies should proactively protect their corporate data through the use of Data Loss Prevention (DLP) systems. If not, they are accepting a needlessly large level of risk.

    Miller also says there has been a tripling of data attacks in its Australian client’s already this year. “And we don’t expect this to diminish,” he warns.

    “Organisations also need to monitor attacks by implementing Web Application Firewalls and Security Information and Event Management (SIEM) systems to detect ongoing attacks.”

    HP: PCs In A Spin As Whitman Plays Hard Ball

    Should we stay or go now? That is the question the troubled computer giant must answer as it sends boss Leo Apotheker packing.


    Click to enlarge

    But newly decorated boss Meg Whitman, the ex eBay Chief credited with turning the e-tailer around during her 10 year reign,  appears to be prepared to take the decision head on, for better or worse.

    “This decision is not like fine wine,” she told analysts last week. “It’s not going to get better with age,” indicating Palo Alto are going to stick with their guns on the fateful ‘decision’ made by her predecessor.

    The ‘decision’ Whitman is referring to is of course Hewlett Packard sounding the death knell for its PC business earlier this year, saying it planned a “spin off” which has irked the industry and shareholders alike.

    “There’s clearly some uncertainty,” declared Todd Bradley, HP’s Personal computing boss, who is currently scurrying around the globe rallying employees and reassuring clients HP is still the stalwart of the hardware industry.

    Read HP To Quit PC & Tablet Market Harvey Norman Set To Hold Urgent Talks Here

    “We’re not being as clear with our own messaging with you as we should be. There’s been broad misinterpretation,” he added.

    Analysts are also indicating Bradley, who was thought to be in the running for the top job, must be fed up with “persuading everyone and their dog that H-P is not getting out of the PC business,” after the shock announcement by the No.1 PC maker by sales.
     
    “It’s got to be frustrating for him, as there are other things he could be doing,” said Garter analyst, Martin Reynolds.

    After joining HP as an executive vice president, Bradley helped build up the computer business his bosses are now looking to get rid of – jaded from low margins and increased competition from Apple in the form of the iPad and Mac. The epic failure of Touch Pad tab was also seen as driving factor. 

    Under Bradley’s reign, the PC revenue were revved up to $41 billion annually from $29 bn, while profit grew almost double to $2bn a year from $1.2 billion, according to the Wall Street Journal, and surpassed rivals Dell to become the largest computer maker.

    However, in the third quarter of this year, HP’s PC revenues fell 3% from 2010 figures and although disappointing was hardly deemed sufficient to shut up shop.

     

    But even though there was rumblings HP was sticking to its controversial decision, Whitman admitted her company must “obviously step back and take a hard look at this.”

    “There are so many things that we need to work through on this spinning,” Mr. Bradley also admitted earlier this month.

    Hello NBN: Telstra Move Closer To $11B Deal

    Telstra has lodged its revised split framework, meaning the $11bn pay off from NBN is a step closer to its coffers.
    The telco’s revised Structural Separation Undertaking (SSU) submitted today to the ACCC, outlines how it intends to break up its retail and wholesale arms during the construction of the $36bn National Broadband Network.

    This means the controversial NBN/Telstra deal may be a step closer, where the telco surrenders all its network infrastructure and cables to NBN Co in return for $11 billion fee, if the Australian Competition and Consumer Commission (ACCC) approves the revised plan.

    Final approval by the competition watchdog will also mean Telstra can go gung-ho on the NBN and release its general strategy, consumer plans and pricing, which Optus has already done, for the high speed fibre broadband services being rollout out this year and beyond.

    The 105-page revised SSU came after multiple rounds of public consultation and criticism from rival telcos.

    However, the ACCC has indicated Telstra had adequately responded to the issues raised, CEO David Thodey said today.

    The changes made to the revised SSU lodged in December include clarification on the operation of the overarching equivalence commitment, and how wholesale customers access reference prices for services.

    Just last week the ACCC set a cap on the wholesale broadband prices Telstra can charge rivals, which, it now appears, the telco are not objecting to, even though it could set the giant back up to $55m in revenue annually.

    Telstra believes the new changes made to the SSU since it was first lodged in July do not constitute material change in the context of the proposed deal approved by shareholders in October last.

    “I am pleased the ACCC has acknowledged that their concerns have been addressed and I note their commitment to consider the SSU promptly,” Thodey said.

     

    Following acceptance of the SSU there is a small number of procedural matters that need to be addressed before the agreements are implemented.

    Read the Telstra submission in full here

    “The break up means it will cease supplying fixed line carriage services to retail customers in Australia using telecommunications networks over which Telstra is in a position to exercise control” and “will not be in a position to exercise control of a company that supplies fixed line carriage services to retail customers in Australia,” the submission confirmed.

    The ACCC confirmed it received the submission today and said it was now moving to finalise its decision on Telstra’s break-up, which it expects to announce “shortly. “

    “This further version addresses those drafting issues raised during the recent consultation process that were of concern to the ACCC,” ACCC chairman Rod Sims said.

    The competition watchdog does not propose to consult further in relation to the revised undertaking, it said.

    Surprise Retail Sales Lift But CE Dips Again

    An unexpected 1.1 percent boost in April retail trade, according to new figures by the Australian Bureau Statistics.This jump (seasonally adjusted) marks the biggest lift in sales so far this year – and was higher than the forecasted a 0.4 percent increase.

    The retail hike, which has been described by one analyst as ‘unexpected’ was attributed to post natural disaster bounce, which afflicted Queensland and Victoria.

    “If we look through the volatility of the last couple of months and focus on the underlying trends, it is one that shows retail spending has lifted from its lows but one in which retail spending growth is relatively weak,” said St George chief economist Besa Deda.

    The boosted retail sales figure for April followed a dip of 0.3 percent in March and a 1.0 percent rise the previous month. Department stores sales figures also buoyed the overall figure, rising 0.3 percent for April.

    The household goods category overall, which includes electronic goods fell -0.1 percent, although seasonally adjusted rose 0.7 percent.

    The trend estimate fell by -0.6% for electrical and electronic goods retailing, although after seasonal adjustments rose to -0.4 percent.

    This will come as no great surprise to many within the electronics industry which has been plagued by price deflation, heavy discounting and intense competition from online rivals.

    Overall, retail in Vic (0.5), Qld (0.5), WA (0.8), NSW (0.2), S A (0.2) N T (1.2) all rose while ACT and Tas witnessed a decline in fortunes.

    In trend terms, Australian turnover rose 2.7 percent in April 2011 compared with the same period last year.

    The Australian Retailers Association (ARA) said the 1.1 percent boost in April retailing was driven by weather conditions and could also be attributed to consumers having more time to shop over the extended Easter break.

     

    ARA Executive Director Russell Zimmerman said department stores had seen a boost in sales for April, but when compared to the same time last year this growth is still below the rate of inflation.

    “Department stores and fashion retailers have posted growth compared to March 2011 because of the earlier, colder weather but retailers aren’t expecting this stronger trade to continue,” Zimmerman said.

    However, May figures will show how consumers have reacted to new taxes announced in the Budget which may cause shoppers to tighten their belts even further, he added.

    “Even though there have been some positive results for April, the modest year- on-year growth is a sign consumers won’t be able to afford any increase to their mortgage repayments if the RBA decides to raise interest rates on Tuesday.

    Vodafone To Unleash New Mobile Plans?

    Vodafone’s mobile plans are to get a makeover, according to sources.

    SmartHouse has been told by a company source of the telco’s intentions to overhaul its mobile post-paid plans.

    The changes will affect plans with contracted phones, while BYO plans will remain untouched, apparently.

    So what will change?

    There may ‘possibly be additional call value and data allowance’ on Vodafone post-paid plans, the source indicated.

    The telco currently offers a total of eight mobile plans – from $30, $40, $50 to $100.

    The news comes just one day after Vodafone changed its Internet data pricing, charging in MB blocks–a move that could push up prices–and are also killing off ‘Infinite’ Facebook and Twitter use for pre-pay users.

    So, if our source is correct, then post paid customers may be better off than pre payers, who are now banished from Infinite social networking as of next month.

    Vodas drop in data pricing is “largely reflective of the way our customers are using data today” and are a part of its effort to reduce costs as users guzzle data.

     
    The charges to data pricing “allow us to invest in a network that will enable the increased access to voice and data our customers are asking for while remaining competitive.”

    Vodafone was also ringing their customers this week, quizzing them over their mobile plans and if they were satisfied with existing allowances, possibly as it prepares to make way for its renewed offering.

    On the prepay front, the red telco insists its still has some of the best value plans in the market including its $30 cap (500MB and $450 flexible credit), compared to rival Telstra’s $30 plan, as it fought off criticism of its recent changes.



    $20,000 4K TV: What’s The Point?

    “Negligible”: Next gen 4K TV may look nice but wont sell, say analysts.


    Click to enlarge

    AS LG gets ready to launch the first 4K Smart TV in OZ this month, new figures suggest the emerging Ultra Hi-Def 4K LCD technology (3,840 by 2,160) or almost 4000 pixels, will fail to make a dent in LCD market.

    4K televisions sport a pixel format four times that of a typical high-definition set (1,920 by 1,080) but is said to have unbelievable depth and screen clarity.

    But demand for ultra-high-definition 4K TVs will remain “negligible for the foreseeable future, with shipments never accounting for more than 1% of the global display (LCD) TV market during the next five years” analysts iHS said today.

    Just 4,000 of the high end 4K TVs are to be shipped this year, although this will rise to 2.1 million in 2017, just 0.8%.

    And that’s at its peak in five years, when 4K tech is far more commonplace.

    LG is to unveil the very first 84″ UD TV to Australia next Tuesday and would not be drawn on expected demand here when contacted by Channel News, saying it will reveal all next week.

    The LG mammoth TV is rumoured to costs around the $20K mark, although this won’t be confirmed until next week’s launch.

    However, 4K is available in other markets including Asia. Sony announced an 84-inch 4K LCD-TV priced at $25,000 in Japan and Toshiba is selling a 55-inch model priced at a more reasonable $10,000.

    Chinese brands Hisense and Konka are also jumping on the 4K bandwagon, although Samsung are backing OLED technology instead, saying the amount of content on 4K is too little.

    But maybe they shouldn’t bother.

    IHS believes that neither consumers nor TV brands will have the interest required to make the 4K LCD-TV market successful.

    This anaemic demand for 4K is despite some several “high profile” launches by big names, analysts note.

    Several consumers CN spoke to that own a HD TV already said they would not spend $20K on a TV.

    “No amount of money I had would justify buying that” one TV user said in an emailed comment.

    “Does this TV happen to be made of gold nuggets?” another quipped.

    “If you have a television that is 60-inches or larger and are watching video that has a 3,840 by 2,160 resolution, then a 4K television makes sense,” said Tom Morrod, director, TV systems IHS.

    But a very limited amount of content is available at 4K resolution, high prices and other issues, are among the issues with  the new technology and “for most people, 1,080p HD resolution is good enough,” IHS notes.

    The market for super-sized, +60″ sets is only 1.5% of total TV shipments in 2012.

     

    The 4K sets are just filling the gap at the high-end TV market until the arrival of the next-generation active-matrix organic light-emitting diodes televisions (AMOLED TVs) arrive, says Morrod.

    “Japanese brands are offering 4K product because they need to have a competitive alternative to the AMOLED TVs being sold by their rivals in South Korea, Samsung and LG Electronics. “

    South Korean companies are having difficulties producing AMOLED panels, saying they will need two more years to achieve competitive volume and pricing, thus are flogging 4K until then.

    iT’s A Sell Out! iPhone 4S Smash ALL Records

    After months of waiting, Apple’s iPhone 4S is finally in town. Approaching the iPhone fanatics lined up outside Apple’s Store in Sydney George St yesterday evening at 6pm for yet another overnight vigil (some have been queuing since mid-week). They seemed in good spirits with less than 12 hours to go to the holy grail that is iPhone 4S, released today in Australia.


    Click to enlarge
    iPhone fans at the top of the queue yesterday evening.

    But it wasn’t just in Sydney where madness was building – Melbourne’s Bourke St appeared also to have a gathering: “quite a crowd building at Melbourne’s Telstra Bourke St store,” one Telstra exec tweeted this morning.

    All 13 Apple Stores opened at the earlier time of 8am and a crowd had also buit at Sydney’s Chadstone Store.

    So, what is all the fuss about, since it appears to not be a major departure from iPhone 4?

    iPhone 4S runs iOS 5, has an 8MP HD video camera, faster dual-core A5 processor, improved antenna and voice activated Siri personal assistant.

    And it appears to be going down a treat, so far: “Ahh, the best phone AND the best coverage RT,” one newly endowned iPhone 4S owner tweeted.

    But the 4S doesn’t come cheap – costing $799 (16GB), $899 (32GB) model and $999 for the new 64GB model.

    It already sold one million units on pre-order worldwide (the biggest ever for an Apple device) with telcos here including Telstra, Optus, Vodafone and Virgin Mobile all vying for lucrative iPhone customer dollars.

    Just moments ago, it emerged Telstra has already sold out all stock – just five hours after the Apple smartphone went on sale, said to be one of the fastest sell out’s ever for an Apple device.

    “64GB models were the first to sell out, followed by 32GB,” said a Telstra spokesperson.

    “Online sales have surpassed all Telstra records reflecting the both the huge demand for iPhone 4S and a growing trend among Australians to buy online.”

    Read Telco iPhone 4S comparo here

    But even Apple co-founder had to line up for the iPhone like everyone else. Steve Wozniack, Steve Jobs Apple co-founder, lined up at 1.20 US local time.

    “The long wait begins. I’m first in line. The guy ahead was on the wrong side and he’s pissed,” he tweeted. 

    Teenage kicks

    No showers, cramped conditions, sleepless nights. Welcome to the bizarre world of iPhone 4S campers.

     

    The iPhone 4S teenage campers in Sydney clearly had the money (and the time) to camp for days on end.
    The teenage duo I spoke to, Tom and Wil, were at the very top of the queue at 6pm yesterday and couldn’t have been more than 16 years old.

    “Why?”, I asked. “Because we want to,” they replied. One of the teens, Tom, was buying the handset for himself and a mate, while Wil just couldn’t face not being the first to get their mitts on the cult-like handset, it appears.

    However, the line up at Apple Store was far less than I anticipated and didn’t even clog the street or go around the corner, yesterday evening at least.

    How were the Apple devotees coping food wise, I wondered or was this an Apple-only  fast? Pedestrians were offering queuers food and many stopped to chat, curious as to why they were lining up.

    iYum: Telstra iPhone 4S cake.

    Telstra, who along with the Apple Store and most other telcos opened their doors at earlier time of 8am to deal with the anticipated iPhone scrum reported at 8:35am this morning: “Heaps of people lined up early to be among the first to purchase a new iPhone 4S.”

    Telstra, who even baked an icake to celebrate the event, were also offering home delivery of the 4S as were Vodafone. 

    However, another Telstra customer was less pleased: “Still waiting for @Telstra to confirm my #Telstra4S order has shipped. Can’t get through on phone. Have submitted form.”

    Another more content fan tweeted: “I have two iPhone 4S handsets on my person right now. I am a mugging waiting to happen.”

     

    Down the road from Apple Store on Sydney’s George St at the Samsung ‘pop-up shop’ there was a similar size queue formed to get their hands on $2 Galaxy SII smartphone to the first ten strore entrants every day this week.


    Click to enlarge