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; } } Matthew Lentini, Author at Smart Office - Page 9 of 13

    Smart Office

    McTiVia Makes Dodgy TV Legal

    A wireless streaming device with a twist takes on the world of content delivery, encouraging users to bend the rules to access content cheaply (and most of the time, free) online.

    With the McTiVia device from Inspire Technology, users are given a trial version of a Virtual Private Network (VPN) that allows them to access geographically restricted content like videos from Hulu.

    Many catch-up TV services in the US restrict content to the one country due to legal licensing restrictions from the content providers. The use of a VPN essentially tricks the services into thinking you are accessing content from the US by going through a foreign IP address.

    “Using a VPN service isn’t illegal,” reassures Ivan Knezevic, product manager for the McTiVia.

    Inspire Technology have posed the idea of products like their own being used as a simple (and legal) alternative to dodgier methods that otherwise involve piracy.

    “This is something that’s a lot easier than downloading a torrent,” adds Knezevic.

    The McTiVia wireless streamer is a small box that acts like a home router, connecting computers to televisions. Rather than sharing content through a link that is then played directly on the TV though, the McTiVia mirrors the image you see on your PC onto your TV – effectively turning your TV into your monitor. And wirelessly.

     

    You can already hardline a PC to a TV (and even record from TV to your PC) with the right video card and a few cables, but McTiVia is aimed at a wider consumer audience.

    “Convenience” is the key, says Robert Bonanno who heads up marketing for Inspire Technology, the newly founded company that’s distributing the McTiVia in Australia.

    With DLNA and other home networking solutions already on the market, Bonanno says that they’re taking a new angle because “DLNA is restricted.”

    While most new TVs can play content straight off USBs and via DLNA, the more obscure file types need specifics codecs through a PC to be played. Even new TVs with browsers have flaws in encoding some browser-based video players.

    “No hardware on the market, that I know of, currently supports Silverlight [apart from PCs],” says Knezevic, pointing out that websites like Nine’s Fixplay catch-up TV service is only compatible on a PC that can run Microsoft’s Silverlight software.

    “They’re trying to make a ‘smart’ TV, but you’ve got the internet which is as smart as it’s ever going to be,” says Bonanno.

    “You’ve got a lot of customers who last year bought a three and a half thousand dollar TV – they’re not going to buy a ‘smart’ TV.”

     

    As for the actual running of the device, it sports a 2.4GHz wireless connection that runs as its own router of sorts, connecting PCs and laptops to a connected TV.

    It’ll run video content with a three second delay as a buffer for audio and video, ensuring that there’s little to no lag in playback, with an option to run in ‘application’ mode where you physically control your PC on a pixel-to-pixel ratio on the screen, but with lag.

    The software supplied is fairly limited though, relying heavily on third party apps to create the truly mobile experience – and continuing the theme of making the dodgy a little more accessible.

    “If you’re tech-savvy and jailbreak your phone, you can get a lot more content off your iPhone,” says Bonanno.

    Applications like Splashtop can mirror a PC or Mac screen onto iPhones and iPads, which can then control the screen, thus controlling what you see on the TV through the McTiVia.

    The McTiVia is currently out at Harvey Norman retailers for $299, though Inspire Technology is in talks with other retailers like Officeworks on widening the distribution network.

    Part of moving to other retailers like Officeworks is to grab the office/business market with office applications like presentations from PC to TV.

    They’re also working on bringing a QWERTY-keyboard remote control with point-and-click cursor functions to take over the need for a mouse and keyboard when using a PC on a TV. This should hit stores in the next month or two for around $99.

    Apple Makes Symbian Look Old Hat

    Apple has taken the lead in the Australian phone market for the first time, gaining 10 per cent market share as Nokia loses that same 10 per cent over the last quarter.Apple currently holds nearly 40 per cent market share following a 13 per cent increase in iPhone shipments over the last quarter according to market intelligence researcher IDC. This increase was shown despite an overall 5 per cent dip year-on-year.

    “Nokia suffered a double whammy, the feature phone market collapsed, with 79% of new mobiles shipped now being smartphones. Meanwhile, Symbian took a huge tumble, as consumers shy away from the platform ahead of Nokia’s transition to Windows Phone,” said Mark Novosel, Telecommunications Analyst, at IDC.

    Symbian is now third in the market at 22 per cent, behind Android which holds roughly 30 per cent.

    “2011 will be an increasingly difficult year for Nokia, as consumers side-step Symbian smartphones and feature phone popularity continues to dwindle,” added Novosel.

    The negative slump could change for Nokia in 2012 as it abandons Symbian and moves to Microsoft’s Windows Phone operating system.

    “Microsoft will also face a tough year with slow Windows Phone 7 growth expected, as the iOS and Android tussle intensifies. As Nokia launches its first Windows Phone models in early 2012, and Symbian shipments eventually stop, Microsoft should start to see an uplift,” said Novosel.

    Acer’s New Ethos Aspires To Cinematic Notebook Computing

    As tipped by SmartHouse early last month, Acer has released a new pair of multimedia notebooks under the Aspire Ethos range that feature a standout design with its detachable touchpad.The original story can be found here.

    The 15.6 inch Aspire 5951G delivers 720p video, while the larger 8951G delivers 1080p video output on its 18.4 inch screen.

    With a focus on media consumption, the two laptops feature Dolby Home Theatre v4 surround sound on their five in-built speakers and subwoofer, as well as an optional Blu-ray or DVD drive for HD movies.

    Apart from being a high-powered machine with its Intel Core i7 processor and Nvidia GeForce GT500 graphics card, the main focus is on its standout piece of design – the detachable touchpad.

    Unique to the new Acer notebooks is the touch-sensitive MediaRemote which doubles as the typical touchpad for the computer. The slide-out remote features quick media launch buttons and dual orientation like a smartphone – a step ahead of the typical pop-out remotes of other media-centric laptops.

    Both laptops are available now, with the Aspire 5951G set at an RRP of $2,399 and the Aspire 8951G set at $2,799.

    Click over to the next page to see the comprehensive list of specs for each model.

     

    Hitachi Joins Sony & Toshiba LCD Screen Merger

    Hitachi is looking to join Toshiba and Sony in merging operations for manufacturing small and mid-sized LCD panels, according to Japanese reports.Toshiba and Sony are said to be in talks to put their units together in a joint venture with part-private, part-public company Innovation Network Corporation of Japan (INCJ) to manufacture LCD screens fit for smartphones and tablets.

    Hitachi is aiming to join in that conversation and reach an agreement with the involved companies in July, according to a report by Japanese news source, Nikkei.

    The Japanese electronics companies, which face heavy competition from their Korean and Chinese neighbours, are putting their operations alongside Japanese government investment through INCJ, potentially selling a multi-billion dollar stake in the new company to the government.

    The talks between Sony and Toshiba originally surfaced earlier this month. The proposal would see manufacture of next-generation OLED panels that could be seen on devices locally as soon as the PlayStation Vita handheld console by Sony is released.

    IBM Expands Cloud Out Of US

    IBM Corp will set up a data centre for its cloud-based LotusLive services in Japan – the first of its kind outside of the US.The data centre, which will be housed in existing IBM Japan centres, will be able to handle millions of users of IBM’s LotusLive collaboration network when it is debuted in late September. The closest hub for these services is currently the US.

    Australia is in a similar situation, set to piggyback off a distant data centre in Singapore for IBM’s SmartCloud enterprise cloud computing service. But IBM engineer Michael Shallcross has expressed his expectation of an Australian server being set up domestically if the demand warrants it in an interview with ITnews.

    HP has also been developing its cloud services, yesterday launching its PC Backup Services for desktop and notebook data back-ups for mid-sized businesses.

    IBM made a similar move on Monday, introducing SmartCloud Archive, SmartCloud Virtualised Server Recovery and SmartCloud Managed Backup, with a focus on fast data recovery for critical business files and documents in times of crisis.

    Samsung Revamps Designer Notebooks From i3 to i7

    Samsung has upped the offerings in its premium class of notebooks with three new models in the Series 9 suite, including an Intel Core i3 version for the budget buyer.Samsung’s answer to Apple’s MacBook Air, Series 9 notebooks throw together high performance with style and durability in a lightweight chassis.

    High performance comes on the back of second generation Intel Core processors (now becoming the norm in new release notebooks) and solid state drives (SSD) instead of typical hard disk drives.

    The weight is dropped on these slim models with their lightweight components and hard duralumin encasings which double as design pieces with their metallic charcoal finish. The award-winning design comes at a high premium price though.

    The three new models include an Intel Core i7, i5 and i3 version, ranging from 13.3 inch screens down to 11.6 inchers.

    “Consumers can now tailor their Samsung Series 9 Notebook purchase to their performance needs and budget, without having to compromise on style or design,” said Samsung’s head of IT, Emmanuele Silanesu.

    An i3 version with a compact 11.6 inch screen in a tiny 1.06kg frame will set buyers back $1,499, but some of the inner detail is cut out of the deal. The SSD is capped at a small 64GB, with no additional memory slots for upgrading RAM and a smaller battery than the i5 and i7 models.

     

    On the plus side, it’s fitted with 4GB of DDR3 RAM, Bluetooth 3.0 compatibility, Micro-HDMI connector, USB 3.0 and 2.0 ports and is the lightest model on offer.

    For a premium on price, there’s the i5 version that, according to Samsung, is the world’s thinnest and lightest i5 13 inch notebook on the market. It’s bigger than the i3 version, but houses more screen real estate and innards than the latter. The SSD is upgraded to 256GB, and the 4GB RAM can be upgraded to 8GB.

    The i5 model sells for $2,299. Add an extra $500 to the price for an i7 model, featuring 8GB RAM as standard on the same 1.31kg body as the i5 version. Apart from the stocked RAM and the better processor, the two laptops are identical.

    The three models are now available for major electronics retailers.

    Review: Optus Smart Safe Eliminates Download Quotas From The Cloud

    The issue that plagues IPTV and cloud services in Australia is that most broadband connections come with a download quota – especially limited on mobile device connections. Optus has used its position as a telecom provider to sidestep the issue and offer cloud storage, minus the download cap.Optus’ Smart Safe is a free mobile-centric cloud service for Optus customers with the hope of enticing customers to pay for larger subscriptions. Optus mobile customers automatically get 500MB of free storage, but can upgrade to 10GB for $5.99 per month, or 300GB for $14.99. The service allows entire backups and restorations of mobile device data on up to five linked devices.

    The Smart Safe app, downloadable for a range of mobile device operating systems, is a simple utility with four main buttons – but it’s a little too simple. There are backup and restore buttons as well as one to manage your subscription and one to display quick, handy tips on using the Smart Safe. The app is not compatible with iPhones though, but works on Android, Windows Phone 6, BlackBerry and Symbian.

    It being a little too simple means that you can’t pick and choose what files you want to upload or download from the mobile app, though there is a settings section for choosing what type of media and content (whether it be music, photos, SMS, contacts, etc) you want to back up. Managing specific files will always lead you back into the less-than-perfect web app rather than using the Android app. Otherwise, you can also customise automatic back up scheduling and caps on backups.

    The web app for browsers on PCs, Macs and mobiles offers a similar feature set, but more in-depth. Files on a computer or saved into the Safe from a linked device can be explored under subheadings like Videos, Contacts, Documents, etc. From here, they can be played, downloaded, edited or shared over social networks.

     

    If you were to lose your mobile phone, all of your data could be replaced onto a new phone by signing the device up to your account, though there’s a cap of five linked devices. If you were to cancel your Optus mobile account, you’re given a 60 day leeway to re-subscribe to Smart Safe and access stored files again.

    The big perk of the unlimited download/upload quota is also only applicable to Optus mobiles rather than desktop broadband connections. There are also charges involved in mobile roaming, though this is switched off by default.

    It’s a good start from a telco jumping into mass consumer cloud offerings, but the process could be a lot more refined with a few app redesigns and tweaks. It’s simple, functional and very useful. Whether you’re paranoid about losing data or want to access all your phone data across devices and computers like Google’s cloud, this service is worth adopting if you’re already with Optus (unless you’re an iPhone user, in which case you’ll be looking out for iCloud).

    Motorola: New 7-Inch Rugged Tablet Has “More Targeted Market Than PlayBook”

    Motorola Solutions has announced a tough-build, 7-inch Android tablet that means business, made especially for bulk-buying enterprise.

    The ET1 features Android 2.3 and runs on a 1GHz dual-core processor with 8GB of internal storage, expandable up to 32GB through microSD. The rugged device is built tough with Gorilla Glass and weighs in at around 600 grams.

    Motorola is burning the bridge between the consumer and enterprise tablet that devices like the BlackBerry PlayBook and the now-defunct HP TouchPad were looking to blur to gain sales in both markets.

    While PlayBook sales have dipped, Motorola Solutions’ director of product marketing, Sheldon Safir, said that the ET1 would pull up better as it “has a much more targeted market than PlayBook.”

    The device is intended for retail and warehouse workers, with Motorola Solutions running a beta program overseas with retailers. The unit is currently Wi-Fi only, but features connecting accessories like barcode readers and magnetic stripe readers.

    The ET1 is set to be sold in bulk to business at a price somewhere under the US$1000 mark. While many competing tablets sit below the $500 mark, Safir said that the expected three to five year device life from the rugged build will outlast consumer devices.

     

    This rugged build features hardened Gorilla Glass and a casing that protects against knocks. The battery is also swappable and can be done without shutting off the device.

    The Android 2.3 software will be customised especially for different organisations, with additives like multiple user log-in software to access different profiles and their applications and documents.

    The device fits into the Motorola Solutions Mobility Services Platform that allows businesses to manage a large fleet of devices with security features like GPS tracking and remote data wipes.

    The ET1 is expected for a late 2011 release.

    iReview iTwin: Scared Of Cloud Security? How About A Physical Alternative With High-Security & Simplicity?

    UPDATED: The iTwin bypasses the virtual world of cloud services to turn your physical storage into its own networking solution.

    This simple solution to remote file access between computers is made up of two USB keys that notch together as a double-ended USB stick. The software is housed in the sticks themselves, so the iTwin is practically plug-and-play on any Windows machine. Forget cloud hosting or remote servers, the iTwin creates its own server through your internet connection with your data housed solely on your computers.

    The two ends of the iTwin come connected and are initially plugged into a computer to install and register the product. From here, the other end is unplugged and slotted into any other Windows machine with a broadband connection, installed and ready to use. A simulated drive is created that files can be drag-and-dropped into to be accessed between the two connected computers. As the physical storage is all held in the computer’s hard drive rather than somewhere online or on the USB sticks, this drive acts as a simple directory to wherever the files or folders inserted are actually saved.

    The iTwin is an attractive option for networking, even physically. The sleek unit comes in a metallic, charcoal colour or lime green, adorned by a blue light on each side to indicate connection and the iTwin logo. The edges are rounded, and the solidly-built units clip smoothly together at the ends. The packaging comes with a simple step-by-step guide that boils this unit down to its base functionality as simply as possible. In other words, anyone can use the iTwin without a lick of tech-savvy.

    The iTwin requires a broadband connection on both ends, and with this can achieve transfer speeds over 3MBps – easily quick enough to instantaneously transfer large documents and images, and still fast for larger media. On each computer, the file transfer is split up into two folders – the local and the remote. Local files are thrown into the local storage folder to be found on the other computer’s remote folder, and vice versa. Being able to see what files are on your main computer and which are stored elsewhere is a particularly handy additive as opposed to sharing one big folder of mixed files stored natively and elsewhere.

    AES 256-bit encryption adds typical security to the file transfers on the iTwin, but needing the have the physical USB sticks connected adds an extra element to security. In the event of losing one or both keys, users can also remotely disable the keys through a code emailed when first registering the product.

     

    With the installed side of the iTwin attached to your main computer (like your home PC, for instance), you’ll need your PC to be constantly on and connected to the internet to be able to access your files remotely from other computers. It’s also limited to Windows and Mac machines, so forget using Android devices with USB ports – browser-based cloud solutions take the lead on this point.

    Unlike Google Docs, you’re never aware of when a shared file is being accessed on two separate computers until you each save the edited file, so if you were to be updating a Word document at home aat the same time as someone else abroad, whoever saves and closes the document last would have a notice telling them the document were modified and that they should rename and save the file separately. It’s not the safest bet for sharing and editing documents on the fly between people, instead working best as a mobile solution for a single user accessing important files away from home.

    If you’re looking for a secure system for remote file access that you can take with you wherever you go, but have the nagging anxiety over storing sensitive data on cloud servers, then the iTwin is a safe bet. It has its limitations, but this single-function unit is an original and effective alternative to cloud services thanks to its physical element, yet with the perk of holding no physical storage in itself. For a single fee, the iTwin is a hybrid service/product to rival conventional methods of file sharing and storage.

    Acer’s New Ethos: Aspire Notebooks With Detachable Touchpads

    The new Acer Aspire Ethos 8951G has taken a new angle on the media remote, with a removable touchpad that doubles as a media remote.The soon-to-be-released step up on the current high-spec 8950G (that sells to the tune of around $2.5k) sports an 18.4 inch screen with a solid state drive and hard drive together under the hood.

    One of its funkiest design fixtures which has been somewhat understated by the company is its chiclet-style remote that doubles as the touchpad. While most media-centric notebooks feature a pop-out remote slotted into the side, the touchpad of the Ethos slides out and displays backlit function touch-buttons.

    Like a typical smartphone, the remote supports dual orientation so it fits in the hand either landscape or portrait.

    With the focus on media, the laptops feature HD display, 5.1 surround sound (with its own inbuilt subwoofer) and in-built Blu-ray writers. The large screen on the 8951G sports the size to fit Full HD 1080p video, and the meat behind the screen to process it.

     

    Acer is also releasing a 15.6 inch model, the 5951G, with similar high performance specs. This screen runs HD video at 1366 x 768 resolution. Each run the latest Intel Sandy Bridge processors that ‘turboboost’ up to 3.4GHz and Nvidia GT500 Series graphics cards that can make short work of most gaming sessions.

    It’s fast when it’s on, and it’s also fast initially turning on. An ‘InstantOn Arcade’ key allows fast-booting into multimedia mode that goes straight into movies, music, photos and other media quicker than a whole boot-up.

    The Acer Aspire Ethos 8951G and its little brother will both be hitting shelves around the end of June. The 8951G will be selling at $2,999, while the 5951G will go for $2,499.