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; } } Mendelson Tiu, Author at Smart Office - Page 9 of 72

    Smart Office

    New HTC Smartphone Larger Than Life

    The new Touch HD from HTC will change the way you look at videos, documents, and websites thanks to its large screen. You can give this phone a go if you hate looking at small screens and want an easy-to-use smartphone, although be prepared to shell out a hefty sum for it.


    Click to enlarge
    The Touch HD’s screen is just as big as my credit card. The 3.8-inch widescreen VGA screen (480 x 800 WVGA) is perfect for the TouchFlo 3D interface: icons were larger and easier to press, while various Windows icons were not as hard to access. Photos and videos were crisp, with the Touch HD being able to change orientation (from portrait to landscape) instantly by rotating the unit.

    The unit only has three hard buttons: the power/standby switch located on the upper right had side of the Touch HD, and the volume keys on the left side. A 3.5mm audio jack is found on top of the unit (finally!), while a mini-USB port for charging and synchronisation is found at the unit’s bottom. The unit’s 5-megapixel camera, microSD card slot, and SIM card slot are found at the back of the device, while four touch keys (end call, pick up, home, back) and secondary camera are found up front.

    Since the unit is a Telstra-exclusive smartphone (as of this time of writing), HTC has decided to change a couple of icons on its TouchFlo interface. It still has the Home, People, Messages, My Email, Photos and Videos, Music, Settings, and Favourite menus but now has a Downloads section (giving users access to Music, Games, Tones and Pics, Caller Tones, Applications, and Bigpond service), a Telstra Applications menu (containing Scan Code, Yellow, Call1234, Whereis Trading Post, CitySearch, Blog and Photos, My Account, My Sync), TV menu (with Entertainment, Sports, News and Docos, Kids, Music, Active, Foxtel, TV, Live, Movies), News and Sport (access to News, Weather, Finance, Sport, Alerts, BigPond, AFL, NRL, V8, Horse Racing), and Internet and Search (launches BigPond, Sensis Search, Yellow, Web, and YouTube).

     


    Click to enlarge
    Despite its large profile, the unit fits comfortably in our hand. The TouchFlo 3D is more responsive now compared to last year’s Diamond, thanks to its 528Mhz Qualcomm processor and 288MB RAM. The unit runs on Windows Mobile 6.1 and comes with pre-installed programs like Office Mobile, Adobe Reader, ActiveSync, RSS feeder, Jetcet Print 5, Windows Live Messenger, and a Remote Desktop Mobile software.

    The unit also comes with Wi-Fi, Bluetooth, GPS, and can quickly download or upload files as it is HSDPA-enabled.

    Despite the unit allowing us to view photos and videos in landscape, we found it strange that the unit cannot change the orientation of our spreadsheet and word documents. It may not be an issue for some users, but after seeing the Samsung Omnia being able to display spreadsheets in landscape, HTC should have done the same.

    The Mobile Foxtel service can be watched in full screen, which is great for mums and dads who want to keep their kids busy for a couple of hours. Music sounded great, with the 3.5mm jack adding more versatility as it allowed us to use our favourite headphones. HTC has also included an FM tuner in case you want to listen to your favourite FM station.

     


    Click to enlarge
    Despite sporting a 5-megapixel sensor, the HTC Touch HD was unable to deliver, providing us with bland photos despite taking shots on well-lit places. And don’t even think about taking shots at night: this smartphone does not have any built-in flash.

    Thanks to its 1350mAh battery, the Touch HD lasted for about three and a half days with moderate use. The company claims that it has a talktime of up to 420 minutes and a standby time of up to 680 hours, which is good for a unit with a large screen.

    HTC has set the bar high this year with its Touch HD. This new phone is bigger, faster, and is very easy to use. The only problem is that you have to shell out $1,499 upfront or $0 upfront on a $150 member plan with a repayment option of $62.45 per month over 24 months for this unit, making it difficult for some to afford this kind of luxurious phone.

    See page over for product specifications and final rating.

     

    HTC Touch HD Specifications:

    Chipset: Qualcomm MSM7201a 528Mhz
    Internal Memory: 512MB flash; 288MB RAM
    Display: 3.8-inch widescreen VGA screen (480 x 800 WVGA)
    Software/OS: HTC TouchFlo 3D with Windows Mobile 6.1 Professional
    Camera: 5-megapixel with auto focus
    Network: WCDMA 850.2100 MHz and GSM: 850/900/1800/1900, HSDPA 7.2 Mbps and HSUPA 2 Mbps
    Memory card: microSD memory card (SDHC capable): 8GB card included
    WLAN: 802.11b/g
    Bluetooth: 2.0 with EDR with A2DP
    GPS: Built-in GPS
    Interface: HTC ExtUSB (mini-USB and audio jack in one; USB 2.0 High-Speed)

    Battery: 1350mAh
    Talk time: WCDMA: up to 420 minutes / GSM: up to 480 minutes
    Standby time: WCDMA: up to 680 hours / GSM: up to 440 hours

    Size: 115 x 62.8 x 12mm
    Weight: 146.4 grams

    HTC Touch HD | $1,499 |  | www.htc.com

    For: Large screen; Big icons; Responsive TouchFlo 3D; Telstra launch icons; 3.5mm audio jack; Good browser; Connectivity; Battery life; Comes with 8GB card
    Against: Spreadsheets and word documents cannot be shifted to landscape; Very expensive
    Conclusion: Big is beautiful with HTC Touch HD

    Fuji Xerox Printers Aim For A Greener Office

    Fuji Xerox has released two new colour laser printers designed for small to medium work groups, which the company says offer superior business productivity to users and is environmentally-friendly.

    According to Fuji Xerox, the DocuPrint C2200 and C3300 DX uses a colour Emulsion Aggregation-High Grade (EA-HG) toner which does not contain fuser oil found in conventional laser printers.  The toner also emits 35 percent less carbon dioxide in its production process compared to conventional toners. The DocuPrint C2200 and C3300 DX are Energy Star compliant and have a power safe mode to reduce the device’s overall energy consumption.


    Click to enlarge
    The DocuPrint C2200 is designed for small to medium work groups while the DocuPrint C3300 DX is ideal for large enterprises and busy workgroups.  Both devices claim to print fast, full colour First Page Time Out speeds of less than 17 seconds and outputs of up to 30 printed pages per minute.

    The units also come with smart printing features that produce impressive graphics, photos and text with Adobe PostScript 3 and PCL6.

    Fuji Xerox Printers Australia and New Zealand’s Marketing Manager, Tom Lewis said, “The DocuPrint C2200 and C3300 DX are a perfect match of speed and beauty.  The ability to print superior colour documents at lighting speed makes these printers the perfect companion for small businesses and large enterprises who demand quality and productivity from a networked printer.” 

     

    Cost conscious businesses will appreciate the Auditron feature in the DocuPrint C2200 and C3300 DX which allows network administrators to limit access to colour printing or set usage limits by user. 

    The DocuPrint C2200 and C3300 DX is bundled with CentreWare Internet Services management tools to simplify the installation and management of these network ready printers.  This browser-based software allows administrators to manage the printer remotely and can be easily configured to alert administrators and users of events such as low toner levels via e-mail. 

    The Docuprint C2200 and C3300 DX have comprehensive networking features for complex business needs and security conscious work environments. These printers support wide area network printing in ERP applications including Citrix, SAP or Fuji Xerox ERP solutions.  Printing over office networks and the Internet is secured by tools such as the IPv6IPSec, IEEE802.1X authentication and SNMPv3 for TCP/IP.

    The DocuPrint C2200 and C3300 DX are available immediately at recommended retail price of AU$1,209 and AU$1,649 including GST respectively through authorised resellers. 

    See: www.fujixeroxprinters.com.au

    3M Introduces Portable Handheld Projector

    The new projector from 3M fits in the palm of your hand and claims to project images, data, and movies onto any flat surface up to 1.2 metres.


    Click to enlarge
    The 3M Micro Professional Projector MPro110 weighs 152 grams and can be connected to a laptop, mobile phone, PDA, or MP4 players. This device claims to have 40 to 60 minutes of battery life, allowing users to use it for sales pitches, presentations, and office meetings.

    The projector uses LED technology to provide up to 10,000 hours of operation. It also has a full VGA resolution that displays in 4:3 format with a wide range of projected image sizes from 127mm during daylight use to 1270mm in a darkened environment.

    The unit comes with an AC adapter, video cable, VGA cable and rechargeable lithium-ion battery. Additional accessories can be purchased separately including a mini-tripod, however, the unit also attaches to any standard size tripod.

    3M’s Micro Professional Projector MPro 110 will be available in April with an RRP of $649

    See: www.3mmmpro.com.au

    Adobe A Good Place To Work Says Survey

    Adobe is one of the best companies to work for according to Fortune Magazine’s 12th annual “100 Best Companies to Work For” survey.

    Adobe bagged 11th place, making this the tenth year Adobe has been on the list. Additionally, Adobe is ranked No. 10 among “top-paying” companies.

    Adobe’s Senior Vice President for Human Resources, Donna Morris said: “Adobe is honoured to be included once again on this distinguished list. In the face of continuing global economic uncertainty, our commitment to keeping Adobe a great place is unwavering, and our ranking speaks to our employees’ enthusiasm about growing their careers here.”

    Adobe has approximately 7,000 employees in locations worldwide, including North America, Europe, Japan and Asia Pacific with more than half of Adobe’s employees located in the United States.

    In total, 353 U.S. companies vied for a place on the “100 Best Companies to Work For” list. Two-thirds of a company’s score is based on the 57-question survey created by the Great Place to Work Institute, a global research and consulting firm with affiliates worldwide. Fortune polled a minimum of 400 randomly selected employees at each company. The remaining third is based on a company’s responses to the Culture Audit questionnaire, which included questions about demographics, pay and benefit programs, and open-ended questions on philosophy, communication and more.

    See: www.adobe.com

    Tough i-Mate Phone For The Outdoors

    i-mate has released a new phone that is built to last, thanks to its lifetime warranty and tough military-grade build.


    Click to enlarge
    The i-mate 810-F runs on Windows Mobile OS 6.1 and is comprised of waterproof rubber casing and exposed metal screws, a full QWERTY keyboard, and impact resistant touch screen.

    According to the company, the 810-F is designed around the stringent MIL-STD-810F series of standards. These standards are issued by the U.S. military’s Developmental Test Command, a body whose role is to ensure equipment can withstand the rigours of the most extreme environments.

    This means that the i-mate 810-F can cope with pressure, heat, water, humidity and even extreme shock. The company also claims that the unit can run at sub-zero temperatures (-10C) and can withstand temperatures of up to 60C. The unit can even be submerged in water.

    i-mate’s CEO, Jim Morrison said, “Until now, users have had to choose between a compact phone that incorporates the latest features, or one that was big, bulky and very expensive that could cope with the rigours of a harsh working environment and survive use during adventurous outdoor pursuits.”

     

    “The 810-F has been developed to meet the demands of the office, the work site and the outdoors.  It is all about performance; whether it’s the ability to perform in extreme conditions, or the performance under its skin. For adventurers looking for a phone to match their lifestyle, it’s the perfect answer,” added Morrison.

    Besides having a lifetime warranty, the 810-F also comes with Secure i-Q, a service from i-mate that lets you use your PC to remotely lock, wipe personal information or alarm your mobile if it’s ever lost or stolen.

    The 810-F is a full-featured Smartphone based on Windows Mobile 6.1 Professional with tri-band HSDPA and quad-band GSM/EDGE connectivity.  Also included is a 320_240 touch screen, 2.2GB of built-in storage, 128MB of DDR memory, 624Mhz PXA processor, 2MP camera with video capability, QWERTY keyboard, GPS, Wi-Fi, digital compass, accelerometer and Bluetooth.

    The i-mate 810-F will be available in the next couple of weeks.

    See: www.imate.com

    Shape Up or Else: ACCC Warns Telcos

    ACCC has issued a warning to the telecommunications industry, saying that it must raise its standards in its treatment of consumers or risk increased scrutiny and action.

    ACCC Chairman, Mr. Graeme Samuel said the ACCC expects carriers to close off access to their mobile networks for rogue operators.

    “Problems such as misleading advertising, unfair contracts and deceptive mobile phone competitions have been allowed to proliferate by service providers, publishers and carriers, who have turned a blind eye while taking a slice of the profits. It is no longer acceptable for carriers to wash their hands of responsibility as operators use their networks to entrap phone company customers with unwanted, expensive and difficult to unwind subscription services,” says Samuel.

    “If all carriers do not exhibit a responsible attitude to closing down rogue operators, they must expect the ACCC to pursue remedies available to it under the Trade Practices Act. Consumer protection issues in telecommunications consistently ranked number one as the sectors most complained about to the ACCC Infocentre, with more than 4,000 complaints a year.”

    The ACCC consistently received complaints about mobile premium services, primarily related to unsolicited services and billing, with about half alleging consumers had received premium services without agreement.

     

    Other concerns included advertising practices; consumers not understanding contracts, including inadvertently signing up to a subscription service; and difficulties with unsubscribing and the complaints handling process.

    “The ACCC is drawing a line in the sand – we’re saying to the poor performers, and there are many of them, mend your ways.”

    A particular concern was the targeting of readers of youth magazines by mobile premium service providers.  He warned the ACCC was prepared to take on publishers for running advertisements which they knew to be misleading or deceptive.

    “Similarly, the ACCC is firmly of the view, that companies which advertising plans as ‘unlimited’ should be very cautious when using such terms. To avoid misleading consumers, any qualifications to ‘unlimited’ calls or SMS messages must be clearly stated and not so significant that they negate the overall impression of the ad,” says Samuel.

    The ACCC also encouraged consumers to make sure they fully understood the terms and conditions of their contracts.

    An Affordable Nokia Smartphone That Can Organise Your Life

    The new Nokia E63 performs just as good as its older brother, the E71, but sports a cheaper price tag. It may miss out on a couple of good features, but then, who is complaining?

    Click to enlarge

    The E63 sports the same design as the E71 but is a bit chunkier. The E63 is 3mm thicker than the E71 (the E63 is 13mm thick), is 2mm wider (E63 is 59mm wide while the E71 is only 57mm wide), and is entirely made out of hard plastic. The QWERTY keypad is definitely ‘bigger’ than the E71, making it easier for users to type e-mails and SMS. The E63 also comes in different colours (our review unit came in blue), which gives it a more personalised touch.

    A 2.36-inch QVGA screen (320×240), light sensor, as well as left and right selection keys, hotkeys (Menu, Calendar, Contact, E-mail), call and end keys, and five-way navigation keys are all located up front, while the unit’s 2-megapixel camera with flash, is located at the back.

    The left spine hosts the microSD card slot and micro-USB connector, while a 3.5mm jack is located on top of the phone. What is missing is the volume rocker, which in our opinion, should have been present. Users would now have to press up or down the navigation key to adjust the volume when talking to a person on the other line. Finally, the E63’s charging port is located at the bottom left part of the unit.

     


    Click to enlarge
    The E63 misses out on HSDPA and GPS (the E71 has it built-in) but still comes with Wi-Fi and Bluetooth. This 3G handset can still push content, but don’t expect downloads to be as quick as other HSDPA-enabled phones in the market. Programs are subdivided into nine different sections (Log, Communication, Connectivity, Download, Tools, Office, Media, Installations, and Web) for easy navigation.

    In order to simplify downloading e-mails, Hutchison 3 users can easily download the ‘Email on 3’ program. This will allow the E63 to automatically retrieve e-mails from a Microsoft Exchange server, Gmail, Yahoo, Hotmail, and e-mail services from other ISPs. The unit can even automatically gather your contact list and save it to the device and update your calendar and to-do list.

    The phone is very simple to use, with Nokia making sure that every day is a stress-free day. The interface is straightforward, the included programs can help business users to be productive while on the road, and the multimedia programs kept us busy during the long commute. The unit can play video files saved in Flash Lite 3, MP4, and 3GP files as well as music files saved in MP3, WMA, AAC, AAC+, and eAAC+. The 3.5mm jack is also a good thing as it allowed us to listen to music using our favourite headphones instead of using the stock buds.

     

    Since the E63 is not HSDPA-enabled, web browsing was a little bit on the slow side. But if you are only going to update your Facebook profile or check the weather, then the E63’s 3G connection should suffice.

    Battery life is good, with the unit lasting for three and a half days. Nokia says that the 1500mAh Li-Po battery will last up to 18 hours (on standby) and has 11 hours of talk time.

    Overall, the Nokia E63 is the perfect smartphone for those who want to receive e-mail on the go. It may not HSDPA and GPS, but since it costs significantly cheaper than the E71, it is not too bad. This phone is currently on 3’s $29 Cap, with unlimited e-mail (Email on 3) being offered by the company for $5 each month. The E63 has an RRP of $509.

    Credit: Hutchison 3

    See page over for product specifications and final rating.

     

    Nokia E63 Specifications

    Size
    * Form: Monoblock with full keyboard
    * Dimensions: 113 x 59 x 13 mm
    * Weight: 126 g
    * Full keyboard
    * High quality QVGA display

    Display and 3D
    * Size: 2.36″
    * Resolution: 320 x 240 pixels (QVGA)
    * Up to 16 million colors
    * TFT active matrix (QVGA)
    * Two customisable home screen modes

    Security features
    * Device lock
    * Remote lock
    * Data encryption for both phone memory an microSD content
    * mobile VPN

    Keys and input method
    * Full keyboard
    * Dedicated one-touch keys: Home, calendar, contacts, and email
    * Speaker dependent and speaker independent voice dialling
    * Intelligent input with auto-completion, auto-correction and learning capability
    * Accelerated scrolling with Navi Key

    Colours and covers
    * Available in-box colours: Ultramarine Blue and Ruby Red

    Connectors
    * Micro-USB connector, full-speed
    * 3.5 mm standard AV connector

    Power
    * BP-4L 1500 mAh Li-Po standard battery
    * Talk time (maximum): GSM up to 11 hours; WCDMA up to 4h 40 min
    * Standby time (maximum): GSM up to 18 days; WCDMA up to 20 days;WLAN idle up to 170 hours
    * Music playback time (maximum): 18 h

    Memory
    * microSD memory card slot, hot swappable, max. 8 GB
    * 110 MB internal dynamic memory

    ————————————
    Nokia E63 | Free on the $29 Cap; $509 |  | www.three.com.au

    For: QWERTY keypad; Wi-Fi and Bluetooth; Office productivity software; Battery Life; Affordable
    Against: No HSDPA and GPS
    Conclusion: An affordable way of keeping in touch.

    Choice Slags Off Printer Manufacturers

    Leading consumer advocate organisation Choice has slagged off printer manufacturers and has accused them of selling inks at exorbitant prices.


    Click to enlarge
    According to Choice, consumers need to be wary of being ripped off by printer inks that cost up to $20 a teaspoon and use microchips to prevent you using cheaper alternatives.

    Tests with 13 multifunction printers showed the cost of ink could be extortionate. Choice says that if you printed five B+W pages, three colour pages and one photo every day for a year costed over three years one brand would cost $9436 to run.

    And while you can buy cheaper genuine replacement cartridges overseas, you often can’t use them with the Australian-bought printer because the microchip attached to the ink cartridge must match the country.

    “They do this to stop legal parallel importation (also known as grey importation). Another effect of the addition of a chip is that third party ink manufacturers have a much harder job competing,” says the report.

    Choice spokesman Christopher Zinn said, “The printer manufacturers own the patents for the chips which means third party competitors can’t legally copy them. The competition is frozen out and consumers pay more.”

    See choice.com.au for the full multifunction printer review and comparison.

    Sony Slims Down Projector Line-Up

    The new projector from Sony weighs 1.7kg and is only 45mm thick, allowing business users to take it along to presentations.


    Click to enlarge
    According to Sony, the VPL-MX20 has brightness level of up to 2,500 lumens, with the 3LCD projection system providing bright and natural images. The VPL-MX20 has also been optimised to provide smooth gradients in dark areas and prevent colour breakup or the rainbow effect.

    Sony Australia’s Projector Product Manager, Vincent Bautista said, “The VPLMX20 is a strong combination of some of Sony’s key projector technologies that can be easily applied across a number of presentation applications. The portability, top end picture reproduction and user features will make the VPLMX20 one of the most appealing data projectors for those presenting on the road.”

    These usability features include Advanced Intelligent Auto Setup, which automatically initiates setup functions by simply turning on the VPLMX20. Additionally, a built-in Auto Focus module and Smart APA (Auto Pixel Alignment) focuses and sizes the projected image for optimum picture performance simply by turning the projector on.

    The Sony VPL-MX20 will be available from mid-April 2009, with its RRP to be announced at a later date.