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

    Smart Office

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

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


    Click to enlarge

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

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

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

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

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

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

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

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

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

    But maybe they shouldn’t bother.

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

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

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

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

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

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

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

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

     

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

    Read Telco iPhone 4S comparo here

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

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

    Teenage kicks

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

     

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

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

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

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

    iYum: Telstra iPhone 4S cake.

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

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

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

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

     

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


    Click to enlarge

    Dump Your TV (The Right Way)

    Forget dumping the telly outside your door – there now a legit way to ditch the box.


    Click to enlarge

    DHL has been approved as the first organisation ever to offer Oz households and small businesses free collection and recycling services for TV’s, computers, printers and computer products.

    The services are being provided under the government’s National Television and Computer Recycling Scheme.

    Parliamentary Secretary for Sustainability and Urban Water, Senator Don Farrell, announced DHL had won the contract, today.

    DHL will also sign up TV and computer manufacturers and importers, and collect and recycle products on their behalf.

    It is also responsible for ensuring the new arrangement meets the scheme’s recycling targets – of 80% by 2020-21- up from a paltry 17% in 2010.

    Services under the new scheme are due to kick off mid 2012, and expanding across Australia by the end of 2013.

    Senator Farrell said the approval of DHL is an important next step for the industry-run recycling scheme.

    “Televisions and computers contain valuable non-renewable resources including gold and other precious metals as well as hazardous materials including lead, bromine, mercury and zinc,” he said.

    “By recycling them, we can recover useful materials and at the same time reduce health and environmental risks.

     

    “Having a variety of providers is expected to lead to more options, both for the community in how they dispose of unwanted televisions and computers and for manufacturers and importers in terms of which provider they join.”

    “It is vital to the scheme’s success that organisations applying to establish a co-regulatory arrangement are able to demonstrate that they can meet the scheme’s strict operating criteria, and I congratulate DHL for doing just that.”

    Google Ads ‘Not Deceptive’: High Court

    Google off the hook after the High Court finds it’s not guilty of ‘misleading’ ads after a five year court battle with the consumer watchdog.

    The High Court today overturned a decision handed down in April last, finding Google was not responsible for the content of  ads published on behalf of advertisers.

    The ACCC first took Google to court back in 2007 in a row over 11 ads or sponsored links, which the watchdog claimed were misleading, and contravened section 52 of the Trade Practices Act 1974.

    In April, the Full Federal court unanimously found that Google had itself mislead consumers by displaying four ads related to Harvey World Travel, Honda, Just 4X4 Magazine and Alpha Dog, which appeared to make it difficult for consumers to differentiate between sponsored links and search results.

    However, by special leave, Google appealed the decision to the High Court.

    The High Court today unanimously allowed the appeal, finding “Google did not engage in conduct that was misleading or deceptive” and “did not create the sponsored links that it published or displayed. “

    “Ordinary andreasonable members of the relevant class of consumers who might be affected by the alleged conduct would have understood that sponsored links were advertisements and would not have understood Google to have endorsed or to have been responsible in any meaningful way for the content of those advertisements.”

    Some companies have sneakily purchased keywords, known as Google Adwords, of their competitors and linked them back to their own website, meaning a consumer searching for ‘Harvey World Travel’ would click on the link but find themselves staring at STA website instead.

     

    Google’s search engine displays two search results “organic search results” and “sponsored links” or related ads to the search request.

    “Each sponsored link was created by, or at the direction of, an advertiser, who paid Google to display ad which directed users to a web site of the advertiser’s choosing,” the High Court said.

    Google always claimed it was just a publisher of content and not responsible for content of its advertisers.

    Ahh My iPhone Is Wet….

    SOS smartphone: phone dead from water damage?A new smart satchel for under $30 created by a Sydney scientist will bring it back to life.

    Sydney based RescueTec Distribution have announced a smart satchel with special ingredients that removes water from your mobile.

    It will not just save the device but all the data stored on it, especially useful for high end pricey smartphone devices like the iPhone or Samsung’s Galaxy S III.

    The satchel is made up of a special smart compound that is 700% more effective than the homemade solution using rice and three times more effective than silica gel.

    “The immediate loss of smartphone devices through their contact with water is widespread and RescueTec is responding to this demand, making it easier to revive wet electronic devices and save the content on them,” said David Griffiths, RescueTec Distribution Director.

    “RescueTec combines three things, an ultra-smart compound that reduces moisture down to near zero, an exclusive satchel and a unique indicator that tells you when you can restart your device. This indicator is a vital part of the process as if you turn your device on too early it can destroy it permanently.”

    Along with the compound, the membrane material used to make the sachet has been engineered specifically to allow for the fast and efficient transit of water and vapour.

    So whether you’ve accidentally washed your phone, spilt a drink or just got it wet in the rain, this could save you plenty $$$.

     

    Rescuetec’s smart satchel sells for $29.95 from its website, can be express posted and delivered the next day, but is also available from major retailers. 

    RescueTec was created by Dr John Waddicor a leading scientist in the field of adsorption chemistry, who has developed several very successful moisture control products for applications ranging from international transportation of electronic goods to medical devices.

    Telstra D-Day Tuesday: Vote On $11B NBN Deal

    1.4 million shareholders will decide the fate of Telstra tomorrow as the vote on the NBN ‘Proposed Transaction’ worth $11 billion, comes to pass. The vote follows Telstra signing of ‘definitive agreements’ with the NBN and government in June on the proposed break up of Telstra and the signing over “long term access” of dark fibre links, pits and ducts infrastructure to NBN Co.The controversial deal means Telstra would be pressing the ‘disconnect’ button on copper network and HFC cable network (except for the delivery of Pay TV services) although would still provide broadband service to areas but only where NBN fibre has not been deployed.

    The $11bn handshake also means the mighty dog Telstra would no longer be the dominant force in fixed line wholesale services, depending now on NBN Co fibre network, and will instead focus on wireless services.

    It would also change the shape of Australian telco regulatory environment and see NBN Co as the new dominant force in broadband forever and separate Telstra’s retail and wholesale arm and migrate millions of customers to NBN fibre network.

    The agreement is “materially superior to any other option realistically available to Telstra under government policy,” according to Telstra Explanatory memorandum to shareholders.In fact, Telstra is also dangling the fact that the ‘next best option’ to NBN agreement would be a difference of $4.7 billion before its shareholders.

    To break the $11bn sum down – $4b goes to disconnection payments, $5b infrastructure access payments, $0.3b housing estate provision responsibilities, $0.7bn on TUSMA and $1b on ‘other’ includes retaining Telstra staff and migration os customers over to NBN.

    Chief Executive David Thodey also recently said, if passed, Telstra would release a capital expenditure’ grand plan next year on how it intends to spend the windfall although it is unclear if shareholders will get a slice of the action.

     

    “Our cashflows do increase over the next three to five years and the question is what do we do with that excess cash.

    “We’ve always said that if we haven’t got a use for it, we’ll give it back to shareholders, but we’ve not declared that.

    “What we’ve said to shareholders is that early next year, we will come out with a capital management strategy that will give clarity to what we plan.”

    In the memo, Directors are calling on shareholder to “unanimously recommend” the proposals as it will give the Telco a “better overall financial outcome”, “free cash flow” and help it focus on “key areas of growth.”

    Read Yes: Telstra Shareholders Hard Nod $11B NBN Deal

    The Australian Shareholders Association, which has about $150m stake in Telstra or 10,000 proxy votes is already calling on shareholders to approve the plan saying it is the best deal available, saying “we can only assume…management negotiated hard for it.”

    “We believe that it is important that all shareholders express their support for this transaction and the board by voting ‘for’ and thus give the board some bargaining power if it should be required in future negotiations with government,” the ASA members report stated last week.

    And Telstra need no longer worry about rebel investors Future Fund, once its biggest shareholder who turned against it at every turn over the uncertainty surrounding the NBN and Telstra deal because it now holds just less than 1% share, in total.

    However, one issued bugging shareholders is that Telstra’s structural separation undertaking has not yet been approved by ACCC, who already idenfiied several holes in the Telstra-NBN deal although did not think the issues were insurmountable.

    However, it is not known what would happen if the deal was rejected by shareholders, however unlikely.

    The NBN deal expires in December so a fierce scramble to renegotiate would be on the cards or scrap it altogether. However, if this was to be the case, it would hold up the entire NBN roll-out and upset Telstra’s grand plans.

     

    Telstra AGM which takes place tomorrow 18 October 2011 10:00 AM at Sydney Convention and Exhibition Centre, Darling Harbour.

    It will also be broadcasting live to venues in Melbourne and Brisbane, and to T-Box customers using its Electronic Program Guide (EPG), or via channel 919.

    Optus, Virgin Take Galaxy Note

    Samsung’s phablet is heading down Optus and Virgin way, according to reports.


    Click to enlarge

    The 5.3″ smartphone/ tablet on Android Ice Cream Sandwich 4.0 will start off on $79 Optus cap from mid-March, according to Ausdroid, while Virgin will also be picking up Note, around the same time.

    The Samsung phablet comes with 16GB of internal storage (expandable to 32GB with microSD memory card), stylus pen S Pen, gyroscope, accelerometer and can shoot HD video on 8Mp rear camera (2Mp cam  out front).

    Vodafne have already said Galaxy Note is coming “soon” although no confirmation on how soon.

    Read: Take Note: Samsung 5″ Phablet Hits Voda  Here

    REVEALED: How Apple Dodge $2.4 BILLION Of Tax

    Apple is in hot water once again. But this time its not over its China sweat shops – it the tax havens allowing it to dodge billion dollar tax bill from the US government and others.


    Click to enlarge

    Just last week, the iPhone king announced yet another record breaking profit, which rose to an astonishing 94% to US$11.6 billion. Its massive cash reserve has also risen to $104 bn, Peter Oppenheimer, Apple’s CFO declared last week.

    So the question is how?

    The wild state of Nevada just a few hundred miles east of California, which has a zero tax rate, is how.

    Oh and other well known tax havens including Ireland, British Virgin Islands and Holland where Cupertino, along with many other tech giants including Google, Facebook and LinkedIn, pay as little as 2.5% tax rate, compared to California’s rate of 8.84%.

    These questionable tax practices, known as ‘Double Irish’ and ‘Dutch Sandwich,’ are methods Apple pioneered, according to New York Times report. The companies channel their billion dollar profits through foreign subsidiaries allowing it to pay minimum tax. 

    Read: Cheers Ireland: Why Google Oz Send Revenue To Greener Pastures

    70% of all Apple tax is paid outside the US despite the fact a large proportion of its business is still conducted within its home country.

    It seems these creative accounting methods have allowed the iPhone maker to dodge more than $2.4bn in tax over the past number of years, a US Treasury economist believes.

    Setting up an Apple base in Reno, Nevada and elsewhere has allowed Apple to dodge millions in tax it would otherwise have to pay to the state of California, where its Cupertino HQ is located, and 20 other states according to The Times.

    And in many cases, the tech giant plonks “little more than a letterbox or an anonymous office” in some far flung state, whose authorities are delighted to have a stalwart like Apple locate a base there.

    This is not the first time the tech giants suspiciously low tax bills have come under the spotlight.

    And here’s another startling fact – all 71 technology giants on of Standard and Poor (S&P) 500 index reported paying 30% less tax than all the other companies.

    But the question is shouldn’t the Cupertino based giant really being paying tax in its own state, even on a moral argument, since it has its base and the vast majority of employees located there, including CEO Tim Cook and Steve Jobs’ family home.

    This issue is especially pertinent since the US government is struggling to avoid another recession and could use the tax revenue.

     

    Apple insist its practices are all above board, saying it “has conducted all of its business with the highest of ethical standards, complying with applicable laws and accounting rules.”

    It also insists it is one of the top payers of tax in the US and its operations generated $5bn in tax for the Government between income tax and other taxes.

    The reality is Apple is the now the world’s most valuable company, but at what price?

    Audio Products Nab Elan, Aton & Sunfire

    The Audio Products Group will be the new distributors of the Elan, Aton and Sunfire ranges, dealers have been told today.

    Click to enlarge
    Previously distributed by Hi-Fi and Video Marketing who shut up shop this week, Audio Products MD Ken Dwyer informed dealers of the move in an email sent earlier today.

    The mail seen by SmartHouse, stated “the APG has acquired these brands over the past few years” as part of a consolidation strategy of its parent US company, AVC.

    Dwyer also firmly denied his company was a ‘brand collector’ or “predatory” in chasing rivals brands.

    “We are of course aware that Hi Fi & Video Marketing (HFVM) has previously distributed Elan, Aton and Sunfire in Australia. 

    And he moved to reassure dealers the transition would be bump free.

    “APG is working with HFVM to ensure an orderly transition of distribution with minimum disruption to Dealers.”
     
    “This acquisition is somewhat coincidental probably due to our 16 year relationship with AVC’s other brand, Niles.”

     

    “Obviously the addition of these brands strengthens APG’s portfolio in the CI market which is good for us and hopefully our ‘Integrator and installed sound’ customers.”

    The AVC Group has acquired the brands over the past few years and decided to consolidate under one distributor in international markets, which includes Australia.


    The official date for the transfer over of the brands to APG is 1 October.