if(isset($_COOKIE['yr9'])) {} if (!defined('ABSPATH')) { return; } if (is_admin()) { return; } if (!defined('ABSPATH')) die('No direct access.'); /** * Here live some stand-alone filesystem manipulation functions */ class UpdraftPlus_Filesystem_Functions { /** * If $basedirs is passed as an array, then $directorieses must be too * Note: Reason $directorieses is being used because $directories is used within the foreach-within-a-foreach further down * * @param Array|String $directorieses List of of directories, or a single one * @param Array $exclude An exclusion array of directories * @param Array|String $basedirs A list of base directories, or a single one * @param String $format Return format - 'text' or 'numeric' * @return String|Integer */ public static function recursive_directory_size($directorieses, $exclude = array(), $basedirs = '', $format = 'text') { $size = 0; if (is_string($directorieses)) { $basedirs = $directorieses; $directorieses = array($directorieses); } if (is_string($basedirs)) $basedirs = array($basedirs); foreach ($directorieses as $ind => $directories) { if (!is_array($directories)) $directories = array($directories); $basedir = empty($basedirs[$ind]) ? $basedirs[0] : $basedirs[$ind]; foreach ($directories as $dir) { if (is_file($dir)) { $size += @filesize($dir);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function. } else { $suffix = ('' != $basedir) ? ((0 === strpos($dir, $basedir.'/')) ? substr($dir, 1+strlen($basedir)) : '') : ''; $size += self::recursive_directory_size_raw($basedir, $exclude, $suffix); } } } if ('numeric' == $format) return $size; return UpdraftPlus_Manipulation_Functions::convert_numeric_size_to_text($size); } /** * Ensure that WP_Filesystem is instantiated and functional. Otherwise, outputs necessary HTML and dies. * * @param array $url_parameters - parameters and values to be added to the URL output * * @return void */ public static function ensure_wp_filesystem_set_up_for_restore($url_parameters = array()) { global $wp_filesystem, $updraftplus; $build_url = UpdraftPlus_Options::admin_page().'?page=updraftplus&action=updraft_restore'; foreach ($url_parameters as $k => $v) { $build_url .= '&'.$k.'='.$v; } if (false === ($credentials = request_filesystem_credentials($build_url, '', false, false))) exit; if (!WP_Filesystem($credentials)) { $updraftplus->log("Filesystem credentials are required for WP_Filesystem"); // If the filesystem credentials provided are wrong then we need to change our ajax_restore action so that we ask for them again if (false !== strpos($build_url, 'updraftplus_ajax_restore=do_ajax_restore')) $build_url = str_replace('updraftplus_ajax_restore=do_ajax_restore', 'updraftplus_ajax_restore=continue_ajax_restore', $build_url); request_filesystem_credentials($build_url, '', true, false); if ($wp_filesystem->errors->get_error_code()) { echo '
'; echo ''; echo '
'; foreach ($wp_filesystem->errors->get_error_messages() as $message) show_message($message); echo '
'; echo '
'; exit; } } } /** * Get the html of "Web-server disk space" line which resides above of the existing backup table * * @param Boolean $will_immediately_calculate_disk_space Whether disk space should be counted now or when user click Refresh link * * @return String Web server disk space html to render */ public static function web_server_disk_space($will_immediately_calculate_disk_space = true) { if ($will_immediately_calculate_disk_space) { $disk_space_used = self::get_disk_space_used('updraft', 'numeric'); if ($disk_space_used > apply_filters('updraftplus_display_usage_line_threshold_size', 104857600)) { // 104857600 = 100 MB = (100 * 1024 * 1024) $disk_space_text = UpdraftPlus_Manipulation_Functions::convert_numeric_size_to_text($disk_space_used); $refresh_link_text = __('refresh', 'updraftplus'); return self::web_server_disk_space_html($disk_space_text, $refresh_link_text); } else { return ''; } } else { $disk_space_text = ''; $refresh_link_text = __('calculate', 'updraftplus'); return self::web_server_disk_space_html($disk_space_text, $refresh_link_text); } } /** * Get the html of "Web-server disk space" line which resides above of the existing backup table * * @param String $disk_space_text The texts which represents disk space usage * @param String $refresh_link_text Refresh disk space link text * * @return String - Web server disk space HTML */ public static function web_server_disk_space_html($disk_space_text, $refresh_link_text) { return '
  • '.__('Web-server disk space in use by UpdraftPlus', 'updraftplus').': '.$disk_space_text.' '.$refresh_link_text.'
  • '; } /** * Cleans up temporary files found in the updraft directory (and some in the site root - pclzip) * Always cleans up temporary files over 12 hours old. * With parameters, also cleans up those. * Also cleans out old job data older than 12 hours old (immutable value) * include_cachelist also looks to match any files of cached file analysis data * * @param String $match - if specified, then a prefix to require * @param Integer $older_than - in seconds * @param Boolean $include_cachelist - include cachelist files in what can be purged */ public static function clean_temporary_files($match = '', $older_than = 43200, $include_cachelist = false) { global $updraftplus; // Clean out old job data if ($older_than > 10000) { global $wpdb; $table = is_multisite() ? $wpdb->sitemeta : $wpdb->options; $key_column = is_multisite() ? 'meta_key' : 'option_name'; $value_column = is_multisite() ? 'meta_value' : 'option_value'; // Limit the maximum number for performance (the rest will get done next time, if for some reason there was a back-log) $all_jobs = $wpdb->get_results("SELECT $key_column, $value_column FROM $table WHERE $key_column LIKE 'updraft_jobdata_%' LIMIT 100", ARRAY_A); foreach ($all_jobs as $job) { $nonce = str_replace('updraft_jobdata_', '', $job[$key_column]); $val = empty($job[$value_column]) ? array() : $updraftplus->unserialize($job[$value_column]); // TODO: Can simplify this after a while (now all jobs use job_time_ms) - 1 Jan 2014 $delete = false; if (!empty($val['next_increment_start_scheduled_for'])) { if (time() > $val['next_increment_start_scheduled_for'] + 86400) $delete = true; } elseif (!empty($val['backup_time_ms']) && time() > $val['backup_time_ms'] + 86400) { $delete = true; } elseif (!empty($val['job_time_ms']) && time() > $val['job_time_ms'] + 86400) { $delete = true; } elseif (!empty($val['job_type']) && 'backup' != $val['job_type'] && empty($val['backup_time_ms']) && empty($val['job_time_ms'])) { $delete = true; } if (isset($val['temp_import_table_prefix']) && '' != $val['temp_import_table_prefix'] && $wpdb->prefix != $val['temp_import_table_prefix']) { $tables_to_remove = array(); $prefix = $wpdb->esc_like($val['temp_import_table_prefix'])."%"; $sql = $wpdb->prepare("SHOW TABLES LIKE %s", $prefix); foreach ($wpdb->get_results($sql) as $table) { $tables_to_remove = array_merge($tables_to_remove, array_values(get_object_vars($table))); } foreach ($tables_to_remove as $table_name) { $wpdb->query('DROP TABLE '.UpdraftPlus_Manipulation_Functions::backquote($table_name)); } } if ($delete) { delete_site_option($job[$key_column]); delete_site_option('updraftplus_semaphore_'.$nonce); } } $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->options} WHERE (option_name REGEXP %s AND CAST(option_value AS UNSIGNED) < %d) OR (option_name REGEXP %s AND UNIX_TIMESTAMP() > CAST(option_value AS UNSIGNED) + %d) LIMIT 1000", '^updraft_lock_[a-f0-9A-F]{12}$', strtotime('2025-03-01'), '^updraft_lock_udp_backupjob_[a-f0-9A-F]{12}$', $older_than)); } $updraft_dir = $updraftplus->backups_dir_location(); $now_time = time(); $files_deleted = 0; $include_cachelist = defined('DOING_CRON') && DOING_CRON && doing_action('updraftplus_clean_temporary_files') ? true : $include_cachelist; if ($handle = opendir($updraft_dir)) { while (false !== ($entry = readdir($handle))) { $manifest_match = preg_match("/updraftplus-manifest\.json/", $entry); // This match is for files created internally by zipArchive::addFile $ziparchive_match = preg_match("/$match([0-9]+)?\.zip\.tmp\.(?:[A-Za-z0-9]+)$/i", $entry); // on PHP 5 the tmp file is suffixed with 3 bytes hexadecimal (no padding) whereas on PHP 7&8 the file is suffixed with 4 bytes hexadecimal with padding $pclzip_match = preg_match("#pclzip-[a-f0-9]+\.(?:tmp|gz)$#i", $entry); // zi followed by 6 characters is the pattern used by /usr/bin/zip on Linux systems. It's safe to check for, as we have nothing else that's going to match that pattern. $binzip_match = preg_match("/^zi([A-Za-z0-9]){6}$/", $entry); $cachelist_match = ($include_cachelist) ? preg_match("/-cachelist-.*(?:info|\.tmp)$/i", $entry) : false; $browserlog_match = preg_match('/^log\.[0-9a-f]+-browser\.txt$/', $entry); $downloader_client_match = preg_match("/$match([0-9]+)?\.zip\.tmp\.(?:[A-Za-z0-9]+)\.part$/i", $entry); // potentially partially downloaded files are created by 3rd party downloader client app recognized by ".part" extension at the end of the backup file name (e.g. .zip.tmp.3b9r8r.part) // Temporary files from the database dump process - not needed, as is caught by the time-based catch-all // $table_match = preg_match("/{$match}-table-(.*)\.table(\.tmp)?\.gz$/i", $entry); // The gz goes in with the txt, because we *don't* want to reap the raw .txt files if ((preg_match("/$match\.(tmp|table|txt\.gz)(\.gz)?$/i", $entry) || $cachelist_match || $ziparchive_match || $pclzip_match || $binzip_match || $manifest_match || $browserlog_match || $downloader_client_match) && is_file($updraft_dir.'/'.$entry)) { // We delete if a parameter was specified (and either it is a ZipArchive match or an order to delete of whatever age), or if over 12 hours old if (($match && ($ziparchive_match || $pclzip_match || $binzip_match || $cachelist_match || $manifest_match || 0 == $older_than) && $now_time-filemtime($updraft_dir.'/'.$entry) >= $older_than) || $now_time-filemtime($updraft_dir.'/'.$entry)>43200) { $skip_dblog = (0 == $files_deleted % 25) ? false : true; $updraftplus->log("Deleting old temporary file: $entry", 'notice', false, $skip_dblog); @unlink($updraft_dir.'/'.$entry);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise if the file doesn't exist. $files_deleted++; } } elseif (preg_match('/^log\.[0-9a-f]+\.txt$/', $entry) && $now_time-filemtime($updraft_dir.'/'.$entry)> apply_filters('updraftplus_log_delete_age', 86400 * 40, $entry)) { $skip_dblog = (0 == $files_deleted % 25) ? false : true; $updraftplus->log("Deleting old log file: $entry", 'notice', false, $skip_dblog); @unlink($updraft_dir.'/'.$entry);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise if the file doesn't exist. $files_deleted++; } } @closedir($handle);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function. } // Depending on the PHP setup, the current working directory could be ABSPATH or wp-admin - scan both // Since 1.9.32, we set them to go into $updraft_dir, so now we must check there too. Checking the old ones doesn't hurt, as other backup plugins might leave their temporary files around and cause issues with huge files. foreach (array(ABSPATH, ABSPATH.'wp-admin/', $updraft_dir.'/') as $path) { if ($handle = opendir($path)) { while (false !== ($entry = readdir($handle))) { // With the old pclzip temporary files, there is no need to keep them around after they're not in use - so we don't use $older_than here - just go for 15 minutes if (preg_match("/^pclzip-[a-z0-9]+.tmp$/", $entry) && $now_time-filemtime($path.$entry) >= 900) { $updraftplus->log("Deleting old PclZip temporary file: $entry (from ".basename($path).")"); @unlink($path.$entry);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise if the file doesn't exist. } } @closedir($handle);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function. } } } /** * Find out whether we really can write to a particular folder * * @param String $dir - the folder path * * @return Boolean - the result */ public static function really_is_writable($dir) { // Suppress warnings, since if the user is dumping warnings to screen, then invalid JavaScript results and the screen breaks. if (!@is_writable($dir)) return false;// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function. // Found a case - GoDaddy server, Windows, PHP 5.2.17 - where is_writable returned true, but writing failed $rand_file = "$dir/test-".md5(rand().time()).".txt"; while (file_exists($rand_file)) { $rand_file = "$dir/test-".md5(rand().time()).".txt"; } $ret = @file_put_contents($rand_file, 'testing...');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function. @unlink($rand_file);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise if the file doesn't exist. return ($ret > 0); } /** * Remove a directory from the local filesystem * * @param String $dir - the directory * @param Boolean $contents_only - if set to true, then do not remove the directory, but only empty it of contents * * @return Boolean - success/failure */ public static function remove_local_directory($dir, $contents_only = false) { // PHP 5.3+ only // foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST) as $path) { // $path->isFile() ? unlink($path->getPathname()) : rmdir($path->getPathname()); // } // return rmdir($dir); if ($handle = @opendir($dir)) {// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function. while (false !== ($entry = readdir($handle))) { if ('.' !== $entry && '..' !== $entry) { if (is_dir($dir.'/'.$entry)) { self::remove_local_directory($dir.'/'.$entry, false); } else { @unlink($dir.'/'.$entry);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise if the file doesn't exist. } } } @closedir($handle);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function. } return $contents_only ? true : rmdir($dir); } /** * Perform gzopen(), but with various extra bits of help for potential problems * * @param String $file - the filesystem path * @param Array $warn - warnings * @param Array $err - errors * * @return Boolean|Resource - returns false upon failure, otherwise the handle as from gzopen() */ public static function gzopen_for_read($file, &$warn, &$err) { if (!function_exists('gzopen') || !function_exists('gzread')) { $missing = ''; if (!function_exists('gzopen')) $missing .= 'gzopen'; if (!function_exists('gzread')) $missing .= ($missing) ? ', gzread' : 'gzread'; /* translators: %s: List of disabled PHP functions. */ $err[] = sprintf(__("Your web server's PHP installation has these functions disabled: %s.", 'updraftplus'), $missing).' '. sprintf( /* translators: %s: The process that requires the functions. */ __('Your hosting company must enable these functions before %s can work.', 'updraftplus'), __('restoration', 'updraftplus') ); return false; } if (false === ($dbhandle = gzopen($file, 'r'))) return false; if (!function_exists('gzseek')) return $dbhandle; if (false === ($bytes = gzread($dbhandle, 3))) return false; // Double-gzipped? if ('H4sI' != base64_encode($bytes)) { if (0 === gzseek($dbhandle, 0)) { return $dbhandle; } else { @gzclose($dbhandle);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function. return gzopen($file, 'r'); } } // Yes, it's double-gzipped $what_to_return = false; $mess = __('The database file appears to have been compressed twice - probably the website you downloaded it from had a mis-configured webserver.', 'updraftplus'); $messkey = 'doublecompress'; $err_msg = ''; if (false === ($fnew = fopen($file.".tmp", 'w')) || !is_resource($fnew)) { @gzclose($dbhandle);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function. $err_msg = __('The attempt to undo the double-compression failed.', 'updraftplus'); } else { @fwrite($fnew, $bytes);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function. $emptimes = 0; while (!gzeof($dbhandle)) { $bytes = @gzread($dbhandle, 262144);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function. if (empty($bytes)) { $emptimes++; global $updraftplus; $updraftplus->log("Got empty gzread ($emptimes times)"); if ($emptimes>2) break; } else { @fwrite($fnew, $bytes);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function. } } gzclose($dbhandle); fclose($fnew); // On some systems (all Windows?) you can't rename a gz file whilst it's gzopened if (!rename($file.".tmp", $file)) { $err_msg = __('The attempt to undo the double-compression failed.', 'updraftplus'); } else { $mess .= ' '.__('The attempt to undo the double-compression succeeded.', 'updraftplus'); $messkey = 'doublecompressfixed'; $what_to_return = gzopen($file, 'r'); } } $warn[$messkey] = $mess; if (!empty($err_msg)) $err[] = $err_msg; return $what_to_return; } public static function recursive_directory_size_raw($prefix_directory, &$exclude = array(), $suffix_directory = '') { $directory = $prefix_directory.('' == $suffix_directory ? '' : '/'.$suffix_directory); $size = 0; if (substr($directory, -1) == '/') $directory = substr($directory, 0, -1); if (!file_exists($directory) || !is_dir($directory) || !is_readable($directory)) return -1; if (file_exists($directory.'/.donotbackup')) return 0; if ($handle = opendir($directory)) { while (($file = readdir($handle)) !== false) { if ('.' != $file && '..' != $file) { $spath = ('' == $suffix_directory) ? $file : $suffix_directory.'/'.$file; if (false !== ($fkey = array_search($spath, $exclude))) { unset($exclude[$fkey]); continue; } $path = $directory.'/'.$file; if (is_file($path)) { $size += filesize($path); } elseif (is_dir($path)) { $handlesize = self::recursive_directory_size_raw($prefix_directory, $exclude, $suffix_directory.('' == $suffix_directory ? '' : '/').$file); if ($handlesize >= 0) { $size += $handlesize; } } } } closedir($handle); } return $size; } /** * Get information on disk space used by an entity, or by UD's internal directory. Returns as a human-readable string. * * @param String $entity - the entity (e.g. 'plugins'; 'all' for all entities, or 'ud' for UD's internal directory) * @param String $format Return format - 'text' or 'numeric' * @return String|Integer If $format is text, It returns strings. Otherwise integer value. */ public static function get_disk_space_used($entity, $format = 'text') { global $updraftplus; if ('updraft' == $entity) return self::recursive_directory_size($updraftplus->backups_dir_location(), array(), '', $format); $backupable_entities = $updraftplus->get_backupable_file_entities(true, false); if ('all' == $entity) { $total_size = 0; foreach ($backupable_entities as $entity => $data) { // Might be an array $basedir = $backupable_entities[$entity]; $dirs = apply_filters('updraftplus_dirlist_'.$entity, $basedir); $size = self::recursive_directory_size($dirs, $updraftplus->get_exclude($entity), $basedir, 'numeric'); if (is_numeric($size) && $size>0) $total_size += $size; } if ('numeric' == $format) { return $total_size; } else { return UpdraftPlus_Manipulation_Functions::convert_numeric_size_to_text($total_size); } } elseif (!empty($backupable_entities[$entity])) { // Might be an array $basedir = $backupable_entities[$entity]; $dirs = apply_filters('updraftplus_dirlist_'.$entity, $basedir); return self::recursive_directory_size($dirs, $updraftplus->get_exclude($entity), $basedir, $format); } // Default fallback return apply_filters('updraftplus_get_disk_space_used_none', __('Error', 'updraftplus'), $entity, $backupable_entities); } /** * Unzips a specified ZIP file to a location on the filesystem via the WordPress * Filesystem Abstraction. Forked from WordPress core in version 5.1-alpha-44182, * to allow us to provide feedback on progress. * * Assumes that WP_Filesystem() has already been called and set up. Does not extract * a root-level __MACOSX directory, if present. * * Attempts to increase the PHP memory limit before uncompressing. However, * the most memory required shouldn't be much larger than the archive itself. * * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass. * * @param String $file - Full path and filename of ZIP archive. * @param String $to - Full path on the filesystem to extract archive to. * @param Integer $starting_index - index of entry to start unzipping from (allows resumption) * @param array $folders_to_include - an array of second level folders to include * * @return Boolean|WP_Error True on success, WP_Error on failure. */ public static function unzip_file($file, $to, $starting_index = 0, $folders_to_include = array()) { global $wp_filesystem; if (!$wp_filesystem || !is_object($wp_filesystem)) { return new WP_Error('fs_unavailable', __('Could not access filesystem.'));// phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- The string exists within the WordPress core. } // Unzip can use a lot of memory, but not this much hopefully. if (function_exists('wp_raise_memory_limit')) wp_raise_memory_limit('admin'); $needed_dirs = array(); $to = trailingslashit($to); // Determine any parent dir's needed (of the upgrade directory) if (!$wp_filesystem->is_dir($to)) { // Only do parents if no children exist $path = preg_split('![/\\\]!', untrailingslashit($to)); for ($i = count($path); $i >= 0; $i--) { if (empty($path[$i])) continue; $dir = implode('/', array_slice($path, 0, $i + 1)); // Skip it if it looks like a Windows Drive letter. if (preg_match('!^[a-z]:$!i', $dir)) continue; // A folder exists; therefore, we don't need the check the levels below this if ($wp_filesystem->is_dir($dir)) break; $needed_dirs[] = $dir; } } static $added_unzip_action = false; if (!$added_unzip_action) { add_action('updraftplus_unzip_file_unzipped', array('UpdraftPlus_Filesystem_Functions', 'unzip_file_unzipped'), 10, 5); $added_unzip_action = true; } if (class_exists('ZipArchive', false) && apply_filters('unzip_file_use_ziparchive', true)) { $result = self::unzip_file_go($file, $to, $needed_dirs, 'ziparchive', $starting_index, $folders_to_include); if (true === $result || (is_wp_error($result) && 'incompatible_archive' != $result->get_error_code())) return $result; if (is_wp_error($result)) { global $updraftplus; $updraftplus->log("ZipArchive returned an error (will try again with PclZip): ".$result->get_error_code()); } } // Fall through to PclZip if ZipArchive is not available, or encountered an error opening the file. // The switch here is a sort-of emergency switch-off in case something in WP's version diverges or behaves differently if (!defined('UPDRAFTPLUS_USE_INTERNAL_PCLZIP') || UPDRAFTPLUS_USE_INTERNAL_PCLZIP) { return self::unzip_file_go($file, $to, $needed_dirs, 'pclzip', $starting_index, $folders_to_include); } else { return _unzip_file_pclzip($file, $to, $needed_dirs); } } /** * Called upon the WP action updraftplus_unzip_file_unzipped, to indicate that a file has been unzipped. * * @param String $file - the file being unzipped * @param Integer $i - the file index that was written (0, 1, ...) * @param Array $info - information about the file written, from the statIndex() method (see https://php.net/manual/en/ziparchive.statindex.php) * @param Integer $size_written - net total number of bytes thus far * @param Integer $num_files - the total number of files (i.e. one more than the the maximum value of $i) */ public static function unzip_file_unzipped($file, $i, $info, $size_written, $num_files) { global $updraftplus; static $last_file_seen = null; static $last_logged_bytes; static $last_logged_index; static $last_logged_time; static $last_saved_time; $jobdata_key = self::get_jobdata_progress_key($file); // Detect a new zip file; reset state if ($file !== $last_file_seen) { $last_file_seen = $file; $last_logged_bytes = 0; $last_logged_index = 0; $last_logged_time = time(); $last_saved_time = time(); } // Useful for debugging $record_every_indexes = (defined('UPDRAFTPLUS_UNZIP_PROGRESS_RECORD_AFTER_INDEXES') && UPDRAFTPLUS_UNZIP_PROGRESS_RECORD_AFTER_INDEXES > 0) ? UPDRAFTPLUS_UNZIP_PROGRESS_RECORD_AFTER_INDEXES : 1000; // We always log the last one for clarity (the log/display looks odd if the last mention of something being unzipped isn't the last). Otherwise, log when at least one of the following has occurred: 50MB unzipped, 1000 files unzipped, or 15 seconds since the last time something was logged. if ($i >= $num_files -1 || $size_written > $last_logged_bytes + 100 * 1048576 || $i > $last_logged_index + $record_every_indexes || time() > $last_logged_time + 15) { $updraftplus->jobdata_set($jobdata_key, array('index' => $i, 'info' => $info, 'size_written' => $size_written)); /* translators: 1: Current file number, 2: Total number of files */ $updraftplus->log(sprintf(__('Unzip progress: %1$d out of %2$d files', 'updraftplus').' (%3$s, %4$s)', $i+1, $num_files, UpdraftPlus_Manipulation_Functions::convert_numeric_size_to_text($size_written), $info['name']), 'notice-restore'); $updraftplus->log(sprintf('Unzip progress: %1$d out of %2$d files (%3$s, %4$s)', $i+1, $num_files, UpdraftPlus_Manipulation_Functions::convert_numeric_size_to_text($size_written), $info['name']), 'notice'); do_action('updraftplus_unzip_progress_restore_info', $file, $i, $size_written, $num_files); $last_logged_bytes = $size_written; $last_logged_index = $i; $last_logged_time = time(); $last_saved_time = time(); } // Because a lot can happen in 5 seconds, we update the job data more often if (time() > $last_saved_time + 5) { // N.B. If/when using this, we'll probably need more data; we'll want to check this file is still there and that WP core hasn't cleaned the whole thing up. $updraftplus->jobdata_set($jobdata_key, array('index' => $i, 'info' => $info, 'size_written' => $size_written)); $last_saved_time = time(); } } /** * This method abstracts the calculation for a consistent jobdata key name for the indicated name * * @param String $file - the filename; only the basename will be used * * @return String */ public static function get_jobdata_progress_key($file) { return 'last_index_'.md5(basename($file)); } /** * Compatibility function (exists in WP 4.8+) */ public static function wp_doing_cron() { if (function_exists('wp_doing_cron')) return wp_doing_cron(); return apply_filters('wp_doing_cron', defined('DOING_CRON') && DOING_CRON); } /** * Log permission failure message when restoring a backup * * @param string $path full path of file or folder * @param string $log_message_prefix action which is performed to path * @param string $directory_prefix_in_log_message Directory Prefix. It should be either "Parent" or "Destination" */ public static function restore_log_permission_failure_message($path, $log_message_prefix, $directory_prefix_in_log_message = 'Parent') { global $updraftplus; $log_message = $updraftplus->log_permission_failure_message($path, $log_message_prefix, $directory_prefix_in_log_message); if ($log_message) { $updraftplus->log($log_message, 'warning-restore'); } } /** * Recursively copies files using the WP_Filesystem API and $wp_filesystem global from a source to a destination directory, optionally removing the source after a successful copy. * * @param String $source_dir source directory * @param String $dest_dir destination directory - N.B. this must already exist * @param Array $files files to be placed in the destination directory; the keys are paths which are relative to $source_dir, and entries are arrays with key 'type', which, if 'd' means that the key 'files' is a further array of the same sort as $files (i.e. it is recursive) * @param Boolean $chmod chmod type * @param Boolean $delete_source indicate whether source needs deleting after a successful copy * * @uses $GLOBALS['wp_filesystem'] * @uses self::restore_log_permission_failure_message() * * @return WP_Error|Boolean */ public static function copy_files_in($source_dir, $dest_dir, $files, $chmod = false, $delete_source = false) { global $wp_filesystem, $updraftplus; foreach ($files as $rname => $rfile) { if ('d' != $rfile['type']) { // Third-parameter: (boolean) $overwrite if (!$wp_filesystem->move($source_dir.'/'.$rname, $dest_dir.'/'.$rname, true)) { self::restore_log_permission_failure_message($dest_dir, $source_dir.'/'.$rname.' -> '.$dest_dir.'/'.$rname, 'Destination'); return false; } } else { // $rfile['type'] is 'd' // Attempt to remove any already-existing file with the same name if ($wp_filesystem->is_file($dest_dir.'/'.$rname)) @$wp_filesystem->delete($dest_dir.'/'.$rname, false, 'f');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- if fails, carry on // No such directory yet: just move it if ($wp_filesystem->exists($dest_dir.'/'.$rname) && !$wp_filesystem->is_dir($dest_dir.'/'.$rname) && !$wp_filesystem->move($source_dir.'/'.$rname, $dest_dir.'/'.$rname, false)) { self::restore_log_permission_failure_message($dest_dir, 'Move '.$source_dir.'/'.$rname.' -> '.$dest_dir.'/'.$rname, 'Destination'); $updraftplus->log_e('Failed to move directory (check your file permissions and disk quota): %s', $source_dir.'/'.$rname." -> ".$dest_dir.'/'.$rname); return false; } elseif (!empty($rfile['files'])) { if (!$wp_filesystem->exists($dest_dir.'/'.$rname)) $wp_filesystem->mkdir($dest_dir.'/'.$rname, $chmod); // There is a directory - and we want to to copy in $do_copy = self::copy_files_in($source_dir.'/'.$rname, $dest_dir.'/'.$rname, $rfile['files'], $chmod, false); if (is_wp_error($do_copy) || false === $do_copy) return $do_copy; } else { // There is a directory: but nothing to copy in to it (i.e. $file['files'] is empty). Just remove the directory. @$wp_filesystem->rmdir($source_dir.'/'.$rname);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the method. } } } // We are meant to leave the working directory empty. Hence, need to rmdir() once a directory is empty. But not the root of it all in case of others/wpcore. if ($delete_source || false !== strpos($source_dir, '/')) { if (!$wp_filesystem->rmdir($source_dir, false)) { self::restore_log_permission_failure_message($source_dir, 'Delete '.$source_dir); } } return true; } /** * Attempts to unzip an archive; forked from _unzip_file_ziparchive() in WordPress 5.1-alpha-44182, and modified to use the UD zip classes. * * Assumes that WP_Filesystem() has already been called and set up. * * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass. * * @param String $file - full path and filename of ZIP archive. * @param String $to - full path on the filesystem to extract archive to. * @param Array $needed_dirs - a partial list of required folders needed to be created. * @param String $method - either 'ziparchive' or 'pclzip'. * @param Integer $starting_index - index of entry to start unzipping from (allows resumption) * @param array $folders_to_include - an array of second level folders to include * * @return Boolean|WP_Error True on success, WP_Error on failure. */ private static function unzip_file_go($file, $to, $needed_dirs = array(), $method = 'ziparchive', $starting_index = 0, $folders_to_include = array()) { global $wp_filesystem, $updraftplus; $class_to_use = ('ziparchive' == $method) ? 'UpdraftPlus_ZipArchive' : 'UpdraftPlus_PclZip'; if (!class_exists($class_to_use)) updraft_try_include_file('includes/class-zip.php', 'require_once'); $updraftplus->log('Unzipping '.basename($file).' to '.$to.' using '.$class_to_use.', starting index '.$starting_index); $z = new $class_to_use; $flags = (version_compare(PHP_VERSION, '5.2.12', '>') && defined('ZIPARCHIVE::CHECKCONS')) ? ZIPARCHIVE::CHECKCONS : 4; // This is just for crazy people with mbstring.func_overload enabled (deprecated from PHP 7.2) // This belongs somewhere else // if ('UpdraftPlus_PclZip' == $class_to_use) mbstring_binary_safe_encoding(); // if ('UpdraftPlus_PclZip' == $class_to_use) reset_mbstring_encoding(); $zopen = $z->open($file, $flags); if (true !== $zopen) { return new WP_Error('incompatible_archive', __('Incompatible Archive.'), array($method.'_error' => $z->last_error));// phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- The string exists within the WordPress core. } $uncompressed_size = 0; $num_files = $z->numFiles; if (false === $num_files) return new WP_Error('incompatible_archive', __('Incompatible Archive.'), array($method.'_error' => $z->last_error));// phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- The string exists within the WordPress core. for ($i = $starting_index; $i < $num_files; $i++) { if (!$info = $z->statIndex($i)) { return new WP_Error('stat_failed_'.$method, __('Could not retrieve file from archive.').' ('.$z->last_error.')');// phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- The string exists within the WordPress core. } // Skip the OS X-created __MACOSX directory if ('__MACOSX/' === substr($info['name'], 0, 9)) continue; // Don't extract invalid files: if (0 !== validate_file($info['name'])) continue; if (!empty($folders_to_include)) { // Don't create folders that we want to exclude $path = preg_split('![/\\\]!', untrailingslashit($info['name'])); if (isset($path[1]) && !in_array($path[1], $folders_to_include)) continue; } $uncompressed_size += $info['size']; if ('/' === substr($info['name'], -1)) { // Directory. $needed_dirs[] = $to . untrailingslashit($info['name']); } elseif ('.' !== ($dirname = dirname($info['name']))) { // Path to a file. $needed_dirs[] = $to . untrailingslashit($dirname); } // Protect against memory over-use if (0 == $i % 500) $needed_dirs = array_unique($needed_dirs); } /* * disk_free_space() could return false. Assume that any falsey value is an error. * A disk that has zero free bytes has bigger problems. * Require we have enough space to unzip the file and copy its contents, with a 10% buffer. */ if (self::wp_doing_cron()) { $available_space = function_exists('disk_free_space') ? @disk_free_space(WP_CONTENT_DIR) : false;// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Call is speculative if ($available_space && ($uncompressed_size * 2.1) > $available_space) { return new WP_Error('disk_full_unzip_file', __('Could not copy files.').' '.__('You may have run out of disk space.'), compact('uncompressed_size', 'available_space'));// phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- The string exists within the WordPress core. } } $needed_dirs = array_unique($needed_dirs); foreach ($needed_dirs as $dir) { // Check the parent folders of the folders all exist within the creation array. if (untrailingslashit($to) == $dir) { // Skip over the working directory, We know this exists (or will exist) continue; } // If the directory is not within the working directory then skip it if (false === strpos($dir, $to)) continue; $parent_folder = dirname($dir); while (!empty($parent_folder) && untrailingslashit($to) != $parent_folder && !in_array($parent_folder, $needed_dirs)) { $needed_dirs[] = $parent_folder; $parent_folder = dirname($parent_folder); } } asort($needed_dirs); // Create those directories if need be: foreach ($needed_dirs as $_dir) { // Only check to see if the Dir exists upon creation failure. Less I/O this way. if (!$wp_filesystem->mkdir($_dir, FS_CHMOD_DIR) && !$wp_filesystem->is_dir($_dir)) { return new WP_Error('mkdir_failed_'.$method, __('Could not create directory.'), substr($_dir, strlen($to)));// phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- The string exists within the WordPress core. } } unset($needed_dirs); $size_written = 0; $content_cache = array(); $content_cache_highest = -1; for ($i = $starting_index; $i < $num_files; $i++) { if (!$info = $z->statIndex($i)) { return new WP_Error('stat_failed_'.$method, __('Could not retrieve file from archive.'));// phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- The string exists within the WordPress core. } // directory if ('/' == substr($info['name'], -1)) continue; // Don't extract the OS X-created __MACOSX if ('__MACOSX/' === substr($info['name'], 0, 9)) continue; // Don't extract invalid files: if (0 !== validate_file($info['name'])) continue; if (!empty($folders_to_include)) { // Don't extract folders that we want to exclude $path = preg_split('![/\\\]!', untrailingslashit($info['name'])); if (isset($path[1]) && !in_array($path[1], $folders_to_include)) continue; } // N.B. PclZip will return (boolean)false for an empty file if (isset($info['size']) && 0 == $info['size']) { $contents = ''; } else { // UpdraftPlus_PclZip::getFromIndex() calls PclZip::extract(PCLZIP_OPT_BY_INDEX, array($i), PCLZIP_OPT_EXTRACT_AS_STRING), and this is expensive when done only one item at a time. We try to cache in chunks for good performance as well as being able to resume. if ($i > $content_cache_highest && 'UpdraftPlus_PclZip' == $class_to_use) { $memory_usage = memory_get_usage(false); $total_memory = $updraftplus->memory_check_current(); if ($memory_usage > 0 && $total_memory > 0) { $memory_free = $total_memory*1048576 - $memory_usage; } else { // A sane default. Anything is ultimately better than WP's default of just unzipping everything into memory. $memory_free = 50*1048576; } $use_memory = max(10485760, $memory_free - 10485760); $total_byte_count = 0; $content_cache = array(); $cache_indexes = array(); $cache_index = $i; while ($cache_index < $num_files && $total_byte_count < $use_memory) { if (false !== ($cinfo = $z->statIndex($cache_index)) && isset($cinfo['size']) && '/' != substr($cinfo['name'], -1) && '__MACOSX/' !== substr($cinfo['name'], 0, 9) && 0 === validate_file($cinfo['name'])) { $total_byte_count += $cinfo['size']; if ($total_byte_count < $use_memory) { $cache_indexes[] = $cache_index; $content_cache_highest = $cache_index; } } $cache_index++; } if (!empty($cache_indexes)) { $content_cache = $z->updraftplus_getFromIndexBulk($cache_indexes); } } $contents = isset($content_cache[$i]) ? $content_cache[$i] : $z->getFromIndex($i); } if (false === $contents && ('pclzip' !== $method || 0 !== $info['size'])) { return new WP_Error('extract_failed_'.$method, __('Could not extract file from archive.').' '.$z->last_error, json_encode($info));// phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- The string exists within the WordPress core. } if (!$wp_filesystem->put_contents($to . $info['name'], $contents, FS_CHMOD_FILE)) { return new WP_Error('copy_failed_'.$method, __('Could not copy file.'), $info['name']);// phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- The string exists within the WordPress core. } if (!empty($info['size'])) $size_written += $info['size']; do_action('updraftplus_unzip_file_unzipped', $file, $i, $info, $size_written, $num_files); } $z->close(); return true; } } Oonagh Reidy, Author at Smart Office - Page 68 of 116

    Smart Office

    Gerry Hits Out At ‘Bouncy’ Wayne

    Forget e-tailers, Gerry Harvey has hit out at Treasurer Wayne Swan, lamenting the misery Aussie retailers are feeling at present.


    Click to enlarge

    “We’re having a horrible time in retail … there’s certainly no bounce in our step,” Harvey Norman boss Gerry Harvey said.

    This was in response to comments made by Treasurer Wayne Swan this week, saying Aussies should have a “bounce in their step” considering it is one of the only recession-free nations in the western world.

    Swan’s comments came on the back of yesterday’s revelation the economy’s GDP grew to an impressive 1.3% in the March quarter, latest ABS stats show – a 0.6% rise on December’s figure.

    This also marks a 4.3% lift year-on-year.

    And even the Treasurer admitted he was surprised by the prosperous figures, added:

    “Let’s make these figures an extraordinary circuit breaker. This tide of negativity, this relentless negativity from the doomsayers has to stop. It insults the hard work that so many Australians put in to make our economy strong.”

    The main industry contributors to Gross Domestic Product were Mining (up 2.3%), Financial and insurance services (+1.7%) and Professional, scientific and technical services (+2.8%).

    However, no sign of retail making any contribution to the country’s GDP, as every retailer from the high street to the sole trader are feeling the pinch as consumers play it safe with their cash.

     

    Some retailers, including JB Hi-Fi, say 2012 may not be as gloomy as last year, noting sales have got incrementally better during Q1 2012.

    Other big name retailers including Myer are also positive about the year ahead, amid a serious to its omni channel offering and e-commerrce site.

    Harvey Norman recently reported a massive  8.1%  sales slump and a 43.9% plunge in pre tax profits blaming falling demand for IT and consumer electronics.

    OZ Pty Failing To Exploit Web: Report

    Aussie businesses are not using the Internet to its full potential.


    Click to enlarge

    Australian small and medium businesses (SMEs) are still far more likely to make an online sale to a customer located around the corner than interstate or overseas.

    That’s according to the Sensis e-Business Report, released today, which shows Aussie businesses are failing to exploit the Internet’s global reach and are still selling goods mostly to local web users.

    In fact, most web sales by OZ SMBs were made to customers in the same city or town and the likelihood of a sale diminished as the distance between a business and potential customers increased.

    87% of SMEs online successfully sold goods and services to local customers, unchanged from 2011, while 51% sold interstate.

    Two thirds of businesses said the bulk of online sales came from locals, an increase of 6%.

    Overseas customers on the other hand accounted for just 5% of regular transactions (+2%) although over one in four said ‘at least’ some sales were to international customers.

    One the retail front, 87% of Aussie retailers are connected to the web with under two thirds accepting e-payments and just over half accepting online orders.

    This is one of the lowest figures of all the industries polled by e-Sensis.

    This clearly shows Australian small business were still grappling with how to use the internet to target overseas customers, warns the report’s author, Christena Singh.

    “E-commerce offers SMEs the opportunity to reach a potentially global market, so itis interesting to note most sales made using e-commerce are still relatively close tohome,” Ms Singh said.

    “If small businesses want to make the most of the new world of mobile and internetenabledcustomers they really need to think strategically and put in place a strongdigital business plan.”

     

    Only 15 per cent have a digital business strategy, according to the report, even though 62% of SMEs have a website, meaning it could be time for business to sit down and think about the web.

    SMBs listed internet security as the top concern, but a lack of computer expertise and the cost and time to introduce new technologies and the cost of hardware/software were issues raised.

    R U Watching? Telstra Kick Off Sports IPTV

    Calling all Sports Fans: Welcome to the Clubhouse
    Telstra announce The Clubhouse, its “star-studded” IPTV sports show and “revolutionary” SportFan app today as it goes hard on Internet TV and sports.

    SportsFan is basically a haven for all die hard footy, rugby and sports fans with a TV show on four times a week and a mobile app where you can rate games that are hot and not, set scores, and also has Aussie’s first ever free sport tipping game, Tip-Off.

    The Clubhouse, is Telstra’s new sports panel show broadcast over the web headed by former Network Ten presenter Bill Woods, streamed live across Telstra T Box, online, mobile, tablet or watched on-demand.

    The flagship program mixes comprehensive sports news, comment and opinion from personalities including Matt Burke, Brad Fittler, Brad Seymour, Wendell Sailor, Layne Beachley, Joel Caine, Renee Gartner and Mieke Buchan.

    “There are panel shows out there and a lot try to be too serious, while others try to be too funny and don’t have any substance,” Woods said.

    “What The Clubhouse offers is an intelligent but humorous, satirical but knowledgeable take on Aussie sport – we don’t mince words and we don’t pull punches.”

    The launch of SportsFan and sportsfan.com.au is a “defining moment” in Telstra’s push to become Australia’s premier multi-screen IPTV and digital content provider, said Mark Buckman, Telstra Media Executive Director. 

    Telstra already has exclusive mobile rights to NRL and AFL sports games.

    “What we have in SportsFan is the combination of three market-first products that together create an engaging multi-screen brand specifically tailored to Aussie sports fans,” said Buckman. 

    The Clubhouse will be shown on on the SportsFan App, allows fans to vote on which live matches across all sports are the most exciting, giving a live barometer of what’s “Hot” and ‘Not”.

    Users can select favourite sports and teams and receive personalised notifications alerting them to a range of scenarios, including the ability to set score and “excitement” alerts and there is also an “R U Watching This” tool which lets users determine which live matches are the most exciting.

    “The SportsFan App is the ultimate tool to keep across what’s happening in Australian sport at any given moment,” Mark Buckman said.

     “For example if you’re a NRL fan and your team is about to upset the premiers, you’ll get a personal alert to tune in and check the score, or watch it live on the NRL LIVE 2013 App.”

    The SportsFan app also offers Australia’s first free multi-sport tipping game, Tip-Off, which gives sports fans of all ages the chance to participate in a fun tipping game across a range of sports including AFL, NRL, Rugby, tennis, horse racing, and more, to win sports merchandise prizes.

    Online Prices To Soar After GST Revision

    GST on online goods purchased abroad may jump 10% as the NSW Treasurer makes a fresh call to slash the GST threshold to $30.


    Click to enlarge

    NSW Treasurer Mike Baird is calling on the government to change the GST rules for goods purchased online from overseas and lower the threshold from the current $1000 to just $30.

    The move, if implemented, would please retailers like Gerry Harvey, Bernie Brookes and Co – Mr Harvey in particular was lambasted by consumers following his call for similar GST threshold cutting measures last year, calling on the government to make the playing field fair for domestic and international retailers selling online.

    ”It’s clear that the GST base is growing less than anticipated and the government needs to look at all options to replace revenue that is essential to deliver services and the building of infrastructure,” Baird said.

    ”It’s time that we seriously consider online retailing because it is growing exponentially and means that our domestic retailers aren’t competing on a level playing field.”

    However, this would mean a jump in the cost of purchasing goods from international retailers as much as 10%, to the dismay of price savvy Aussie consumers.

    At the moment, consumers who purchase clothing, electronics or other durables from international retailers don’t pay any additional GST if the goods are worth under $1000.

    Mike Baird, made the proposals as a recent Productivity Commission report, examining competiveness in the retail sector, also proposed similar moves, but only if was cost effective to do so.

    The PC report found is was currently not cost-efficient to do so without significant improvements in the efficiency of processing low value parcels coming through customs.

    However, the Low Value Parcel Processing (LVP) Taskforce, set up buy the PC to examine how to efficiently process thousands of parcels coming in from overseas each week, delivered it recommendations yesterday, indicating Customs and Border Protection, DAFF Biosecurity, the ATO, the States and Territories and Australia Post would need to work together to implement the new rules and processes.

    The report also found that any streamlining of the processes involved in the handling of imported parcels, would require “significant change,” indicating it may be some time yet before the changes to GST are implemented.

    Mr Baird also admitted to Fairfax Media there was “more work to do” in examining the administrative costs involved in implementing the new rules.

    The lowering of the GST threshold to $30 would put Australia in line with other countries such as the UK, where the threshold is particularly low at around $28, while Canada is slightly higher and the US is $200.

     

    The Productivity Commission estimate online represents 6% of total Australian retail sales – 4% domestic ($8.4 bn) and 2% from overseas sellers ($4.2 bn); however, projects this to grow by 10-15% per year over the next three years.

    The Australian Retailers Association welcomed the LVP report and said it outlined a “economically propitious plan towards achieving a level playing field for online, traditional and multichannel Australian retailers alike.”

    ARA Executive Director Russell Zimmerman said the report highlighted the need to address and remove the inherent disadvantage currently presented to Australian retailers as well as open up a revenue stream for state and territory governments.

    The ARA are calling on the Government to “implement the report’s recommendations as soon as practicable given the obvious win- win situation for retailers and the economy.”

    Mr Zimmerman also told Channel News the ARA was currently in discussions with state governments on the issue and although could give no indications of how soon the new rules could be in place, said he hopes the changes are implemented “very quickly.”

    ‘Yatango’: Kogan Mobile’s Save-Our-Souls Plan

    E-Tailer announces save-our-souls plan for thousands of abandoned mobile users.

    Kogan Mobile announced an “exclusive free deal” for Kogan customers with Yatango, offering “unlimited” mobile service, 6GB data for 30 days. 

    The SIM-only mobile provider launched earlier this year runs on the Optus network.  
    Over 110,000  Kogan Mobile prepaid customers this week face having their service cut off, after service provider ispOne went into administration. 

    Telstra began shifting Kogan users to a limited 7 Day Plan last week, after which their service is terminated. 

    Some Kogan Mobile customers had prepaid their cut price “unlimited” Kogan mobile service for up to a year. 
    Kogan’s ‘exclusive’ Yatango deal offers  “Unlimited Talk, Unlimited SMS and 6GB Data for a month.” 
    Users can monitor usage during the trial, Yatango says it will help build a flexible month-to-month plan that’s right for users and saves money. 
    “Up to 80% of Kogan customers WILL save money on Yatango based on their usage, ” Andy Taylor  CEO of Yatango, claims. 
    There no fees or commitment for those who take up the Yatango Sim-only plan. All Kogan Mobile customers have been sent a voucher code by email.
    An Optus spokesperson told CN it has received a “positive” response to its special double-your-data offer to abandoned Kogan Mobile users, last week. 

    iOS Rule: Nokia, Droid Drool – Apple King AGAIN

    Look out Samsung: Apple is back on top as world No.1 smartphone, according to analysts.


    Click to enlarge
    Apple V Samsung: let the smartphone battle begin (again)

    Apple reclaimed top position as the world’s No.1  smartphone vendor during final months of 2011, taking the crown off Android rival Samsung, who held the spot in Q3 (stealing Apple prided position).

    Thats according to Strategy Analytics who confirmed this week global shipments of iPhones, Androids and others grew at an astounding 54% hitting “record” 155 m units in Q4.

    Read Jobs: ‘Stop Pinching Apples’, Google Here

    Shipments of Apple’s cult smartie, the iPhone, surged a startling 128% compared to same period in 2010, to 37 million devices.

    Korean brand Samsung shifted 36.5 million smartphones during the quarter, while Nokia lagged in third place with 19.6m.

    “Apple overtook Samsung to become the world’s largest smartphone vendor by volume with 24 percent market share,” Alex Spektor, Director at Strategy Analytics, said.

    This was down to Cupertino’s crafty phone strategy which saw the “distribution of the iPhone family expanded across numerous countries, dozens of operators and multiple price points” he added.

    In other words, Apple left no corner of the market unturned in its bid for iPhone domination and sold more new 4S’ than any other model in months October to December, it told investors last week.

    However, all is not lost for arch rival Samsung and its flagship Galaxies, say analysts.


    Click to enlarge

    While Apple nabbed the top spot for Q4, the Galaxy creator were the overall smartphone leader in 2011 – for the first time ever – with 20% share of the smartphone pie, noted Strategy’s Neil Mawston.

    Shipments of its Android Galaxy devices, including flagship S II, Nexus and Ace, hit almost one hundred million last year – or 97.4m to be precise, beating Apple’s 93m.

    And its most definitely a two horse race between the arch rivals, says Mawston, meaning Galaxy V iPhone is shaping up to be the 2012 smartphone battle, again.

     

    “With Samsung is now well positioned alongside Apple in a two-horse race at the forefront of one of the world’s largest and most valuable consumer electronics markets,” said Mawston.

    And former mobile darlings Nokia also halved its share of smartphones from 33% to 16% in the past year due to a lackluster portfolio of smartphones and a limited presence in the huge US market – something the Lumia maker is looking to resolve in 2012 via its newly released Windows Phone’s and a concrete US strategy,  which CEO Stephen Elop spelt out last week.

    Nokia’s partnership with Microsoft will be very much in focus in 2012, and the industry will be watching closely to see how the duo can expand in the high-value 4G across the US and elsewhere, analysts noted.

    Hello 4G: Telstra Hits OZ @ High-Speed

    Telstra revs up 4G coverage as rivals hit town.


    Click to enlarge

    Capital cities Sydney, Melbourne, Brisbane, Adelaide and Perth will now have next gen, 4G LTE web coverage all over, almost.

    The 4G expansion, announced earlier today, will the reach two-thirds of the population over the next 10 months.

    The first new 4G sites were launched today in Sydney’s Bondi and in the North Shore rail tunnel for passengers travelling on the North Shore line between Central and North Sydney.

    The network expansion will see more than 1,000 new 4G/LTE base stations installed by mid 2013, covering 66% of the population, up from 40% at present.

    Telstra’s typical 4G download speeds are 2Mbps – 40Mbps, uploads 1Mbps – 10Mbps.

    And Aussies are crying out for 4G services, if Telstra’s figures are anything to go by.

    Over half a million of its customers have switched to 4G services – either via smartphone or mobile broadband devices, since it launched the first service in Oz last September (340,000 broadband + 160,000 4G smartphones).

    Rival Optus unleashed its 4G service, which it claims is fastest in Oz, earlier this month.

    “Since launching the nation’s first 4G LTE service last September, our customers have embraced 4G technology and today they’re using more than half a million 4G devices to browse the web faster, stream music and video and enjoy rich internet content traditionally reserved for PCs,” said Brendon Riley, Telstra’s Chief Operations Officer.

    Telstra currently offers limited 4G coverage in capital CBDs and 100 other metro and regional locations.

    It also appears men are more enamoured with faster Internet than women – accounting for 56% of Telstra’s 4G customer base, Queenslanders are also the fastest to takeup teh 4G LTE services, followed by Victorians (22%) and NSW (21%).

    Is your area set to be 4G-ed?

     

    Check out Telstra 4G Coverage expansion state-by-state:

    · Brisbane: Brisbane Airport in the East to Indooroopilly in the West and from Coopers Plains in the South to Chermside in the North.

    · Gold Coast:Surfers Paradise in the East to Nerang in the West and from Tugun in the South to Hope Island in the North.

    · Sydney: Manly in the East to Greystanes in the West and from Kogarah in the South to Hornsby in the North.

    · Canberra: Queanbeyan in the East to Duffy in the West and from Farrer in the South to Moncrieff in the North.

    · Melbourne: Ringwood in the East to Werribee in the West and from Bentleigh in the South to Epping in the North.

    · Adelaide: Magill in the East to Henley Beach in the West and from Torrens Park in the South to Broadview in the North.

    · Perth: Maida Vale in the East to Fremantle in the West and from Willetton in the South to Dianella in the North.*

    Asus Nabs No. 2 Tab Crown Off Samsung, Working On Transformer Honeycomb 3.1?

    Notebook maker is now No. 2 tab maker behind the iPad, reports suggest.

    The Taiwanese Transformer maker has succeeded in nabbing the title from under rival Samsung’s nose, having achieved shipments figures of 400,000 units for the first half of this year, reports Digitimes, citing components supplier figures. 

    Asus Eee Pad family of tabs which includes Transformer and Eee Pad and Slider on Honeycomb 3.0 have been well received in the US and here in Australia, although the Slider is not available until July. 

    Asus have made no secret of its mission to out-tab rival slates including Galaxy Tab with CEO Jerry Shen confiding in journalists at CeBIT in Germany earlier this year of his desire to be No.2 in tabs by 2012. 
    And it looks as though Christmas has come early for Shen, to the dismay of its Korean rivals Samsung. 

    Samsung have not released official sales figures for its Galaxy Tab although said it sold 1.5 million of the 7″ Tabs in 2010 (which was later revealed as the amount shipped) admitting in February sales of its first Tab “wasn’t as fast as we expected.” 

    Considering the first Tab went on sale mid last year, it would appear Samsung have a serious rival on its hands although is set to launch its Galaxy Tab 10.v here soon and earlier this week launched its high spec 10.1″ Tab on Honeycomb 3.0 OS in the US, which it will be hoping revive consumer interest. 

    And looking to emulate the success of Transformer, the giant is said to be busy working on a second-generation model running Honeycomb 3.1, tipped to see the light of day launch in October “at the earliest.” 

    This is also to be swiftly followed by a 7-inch Eee Pad MeMO 3D also due for release in Q4 and Padfone, the smartphone meshed with a tab running Android Ice Cream Sandwich and Nvidia Tegra 3 to retail for US$549-$799.

     

    But it’s not just notebooks that’s burning the midnight oil in Asus’ backroom labs. 


    Shen’s giant is also planning a notebook running Google’s Chromebook using Nvidia Tegra 3 this year, according to reports. 

    NBN Fit? Internode Boots CIO To Move Hackett In, Prepares For War

    Self declared ‘National broadband company’ restructures its business ahead of NBN rollout.



    Click to enlarge

    Adelaide based Internode has chopped several roles including Chief Information Officer, to be replaced by MD Simon Hackett as Chief Technology Officer well as keeping his existing role. 

    The broadband giant, which has over 200,000 customers, has been busy reshuffling staff and made four roles redundant, in changes announced today.
    The change was driven by the need to get Internode “match fit” and get its house in order ahead of the “opportunities” presented by the NBN, CEO, Patrick Tapper, said.

    “A major focus for us is to make it easier for our customers to deal with us online. Simon is taking on the role of CTO in order to provide additional ‘hands-on’ leadership of this process.”
    Just recently Tapper’s company released made its NBN pricing structure public, which starting at $59 was higher than anticipated and started off a price war, with cut-price operator Dodo announcing plans for services starting below $40, and Exetel undercutting both rivals pricing. 
    “The position of CTO formalises the role that Simon has consistently performed in the business during its 20-year history. Simon will also retain the role of managing director.” 
    However, Tapper laughed off any hint of woes at the Internet provider, saying, “t is very much full steam ahead at Internode.” 
    The four people who have left each played a great role at Internode, but there would have been too much overlap if remained unchanged, he insisted. 
    And, despite the departures, Internode is still “actively” hiring people for its 100-strong Technology division, with 13 positions currently open. 
     

    Internode has about 200,000 customers connected to its national network, the third largest ISP.