/** * Extracts a file or files from the .tar.gz contained in data. * * - Detects if the file is really a .zip file, and if so returns the result of read_zip_data * * if destination is null * - returns a list of files in the archive. * * if single_file is true * - returns the contents of the file specified by destination, if it exists, or false. * - destination can start with * and / to signify that the file may come from any directory. * - destination should not begin with a / if single_file is true. * * - existing files with newer modification times if and only if overwrite is true. * - creates the destination directory if it doesn't exist, and is is specified. * - requires zlib support be built into PHP. * - returns an array of the files extracted on success * - if files_to_extract is not equal to null only extracts the files within this array. * * @package Packages * @param string $data * @param string $destination * @param bool $single_file = false, * @param bool $overwrite = false, * @param string[]|null $files_to_extract = null * @return string|false */ function read_tgz_data($data, $destination, $single_file = false, $overwrite = false, $files_to_extract = null) { require_once SUBSDIR . '/UnTgz.class.php'; $untgz = new UnTgz($data, $destination, $single_file, $overwrite, $files_to_extract); // Choose the right method for the file if ($untgz->check_valid_tgz()) { return $untgz->read_tgz_data(); } else { unset($untgz); return read_zip_data($data, $destination, $single_file, $overwrite, $files_to_extract); } }
function read_tgz_data($data, $destination, $single_file = false, $overwrite = false, $files_to_extract = null) { // Make sure we have this loaded. loadLanguage('Packages'); // This function sorta needs gzinflate! if (!function_exists('gzinflate')) { fatal_lang_error('package_no_zlib', 'critical'); } umask(0); if (!$single_file && $destination !== null && !file_exists($destination)) { mktree($destination, 0777); } // No signature? if (strlen($data) < 2) { return false; } $id = unpack('H2a/H2b', substr($data, 0, 2)); if (strtolower($id['a'] . $id['b']) != '1f8b') { // Okay, this ain't no tar.gz, but maybe it's a zip file. if (substr($data, 0, 2) == 'PK') { return read_zip_data($data, $destination, $single_file, $overwrite, $files_to_extract); } else { return false; } } $flags = unpack('Ct/Cf', substr($data, 2, 2)); // Not deflate! if ($flags['t'] != 8) { return false; } $flags = $flags['f']; $offset = 10; $octdec = array('mode', 'uid', 'gid', 'size', 'mtime', 'checksum', 'type'); // "Read" the filename and comment. // !!! Might be mussed. if ($flags & 12) { while ($flags & 8 && $data[$offset++] != "") { continue; } while ($flags & 4 && $data[$offset++] != "") { continue; } } $crc = unpack('Vcrc32/Visize', substr($data, strlen($data) - 8, 8)); $data = @gzinflate(substr($data, $offset, strlen($data) - 8 - $offset)); // smf_crc32 and crc32 may not return the same results, so we accept either. if ($crc['crc32'] != smf_crc32($data) && $crc['crc32'] != crc32($data)) { return false; } $blocks = strlen($data) / 512 - 1; $offset = 0; $return = array(); while ($offset < $blocks) { $header = substr($data, $offset << 9, 512); $current = unpack('a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1type/a100linkname/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor/a155path', $header); // Blank record? This is probably at the end of the file. if (empty($current['filename'])) { $offset += 512; continue; } if ($current['type'] == 5 && substr($current['filename'], -1) != '/') { $current['filename'] .= '/'; } foreach ($current as $k => $v) { if (in_array($k, $octdec)) { $current[$k] = octdec(trim($v)); } else { $current[$k] = trim($v); } } $checksum = 256; for ($i = 0; $i < 148; $i++) { $checksum += ord($header[$i]); } for ($i = 156; $i < 512; $i++) { $checksum += ord($header[$i]); } if ($current['checksum'] != $checksum) { break; } $size = ceil($current['size'] / 512); $current['data'] = substr($data, ++$offset << 9, $current['size']); $offset += $size; // Not a directory and doesn't exist already... if (substr($current['filename'], -1, 1) != '/' && !file_exists($destination . '/' . $current['filename'])) { $write_this = true; } elseif (substr($current['filename'], -1, 1) != '/') { $write_this = $overwrite || filemtime($destination . '/' . $current['filename']) < $current['mtime']; } elseif ($destination !== null && !$single_file) { // Protect from accidental parent directory writing... $current['filename'] = strtr($current['filename'], array('../' => '', '/..' => '')); if (!file_exists($destination . '/' . $current['filename'])) { mktree($destination . '/' . $current['filename'], 0777); } $write_this = false; } else { $write_this = false; } if ($write_this && $destination !== null) { if (strpos($current['filename'], '/') !== false && !$single_file) { mktree($destination . '/' . dirname($current['filename']), 0777); } // Is this the file we're looking for? if ($single_file && ($destination == $current['filename'] || $destination == '*/' . basename($current['filename']))) { return $current['data']; } elseif ($single_file) { continue; } elseif ($files_to_extract !== null && !in_array($current['filename'], $files_to_extract)) { continue; } package_put_contents($destination . '/' . $current['filename'], $current['data']); } if (substr($current['filename'], -1, 1) != '/') { $return[] = array('filename' => $current['filename'], 'md5' => md5($current['data']), 'preview' => substr($current['data'], 0, 100), 'size' => $current['size'], 'skipped' => false); } } if ($destination !== null && !$single_file) { package_flush_cache(); } if ($single_file) { return false; } else { return $return; } }
/** * Extracts a file or files from the .tar.gz contained in data. * * - Detects if the file is really a .zip file, and if so returns the result of read_zip_data * * if destination is null * - returns a list of files in the archive. * * if single_file is true * - returns the contents of the file specified by destination, if it exists, or false. * - destination can start with * and / to signify that the file may come from any directory. * - destination should not begin with a / if single_file is true. * * - existing files with newer modification times if and only if overwrite is true. * - creates the destination directory if it doesn't exist, and is is specified. * - requires zlib support be built into PHP. * - returns an array of the files extracted on success * - if files_to_extract is not equal to null only extracts the files within this array. * * @package Packages * @param string $data * @param string $destination * @param bool $single_file = false, * @param bool $overwrite = false, * @param string[]|null $files_to_extract = null * @return string|false */ function read_tgz_data($data, $destination, $single_file = false, $overwrite = false, $files_to_extract = null) { // Make sure we have this loaded. loadLanguage('Packages'); // This function sorta needs gzinflate! if (!function_exists('gzinflate')) { fatal_lang_error('package_no_zlib', 'critical'); } umask(0); if (!$single_file && $destination !== null && !file_exists($destination)) { mktree($destination, 0777); } // No signature? if (strlen($data) < 10) { return false; } // Unpack the signature so we can see what we have $header = unpack('H2a/H2b/Ct/Cf/Vmtime/Cxtra/Cos', substr($data, 0, 10)); $header['filename'] = ''; $header['comment'] = ''; // The IDentification number, gzip must be 1f8b if (strtolower($header['a'] . $header['b']) != '1f8b') { // Okay, this is not a tar.gz, but maybe it's a zip file. if (substr($data, 0, 2) === 'PK') { return read_zip_data($data, $destination, $single_file, $overwrite, $files_to_extract); } else { return false; } } // Compression method needs to be 8 = deflate! if ($header['t'] != 8) { return false; } // Each bit of this byte represents a processing flag as follows // 0 fTEXT, 1 fHCRC, 2 fEXTRA, 3 fNAME, 4 fCOMMENT, 5 fENCRYPT, 6-7 reserved $flags = $header['f']; // Start to read any data defined by the flags $offset = 10; // fEXTRA flag set we simply skip over its entry and the length of its data if ($flags & 4) { $xlen = unpack('vxlen', substr($data, $offset, 2)); $offset += $xlen['xlen'] + 2; } // Read the filename, its zero terminated if ($flags & 8) { while ($data[$offset] != "") { $header['filename'] .= $data[$offset++]; } $offset++; } // Read the comment, its also zero terminated if ($flags & 16) { while ($data[$offset] != "") { $header['comment'] .= $data[$offset++]; } $offset++; } // "Read" the header CRC if ($flags & 2) { $offset += 2; } // $crc16 = unpack('vcrc16', substr($data, $offset, 2)); // We have now arrived at the start of the compressed data, // Its terminated with 4 bytes of CRC and 4 bytes of the original input size $crc = unpack('Vcrc32/Visize', substr($data, strlen($data) - 8, 8)); $data = @gzinflate(substr($data, $offset, strlen($data) - 8 - $offset)); // crc32_compat and crc32 may not return the same results, so we accept either. if ($data === false || $crc['crc32'] != crc32_compat($data) && $crc['crc32'] != crc32($data)) { return false; } $octdec = array('mode', 'uid', 'gid', 'size', 'mtime', 'checksum', 'type'); $blocks = strlen($data) / 512 - 1; $offset = 0; $return = array(); // We have Un-gziped the data, now lets extract the tar files while ($offset < $blocks) { $header = substr($data, $offset << 9, 512); $current = unpack('a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1type/a100linkname/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor/a155path', $header); // Clean the header fields, convert octal ones to decimal foreach ($current as $k => $v) { if (in_array($k, $octdec)) { $current[$k] = octdec(trim($v)); } else { $current[$k] = trim($v); } } // Blank record? This is probably at the end of the file. if (empty($current['filename'])) { $offset += 512; continue; } // If its a directory, lets make sure it ends in a / if ($current['type'] == 5 && substr($current['filename'], -1) != '/') { $current['filename'] .= '/'; } // Build the checksum for this file and make sure it matches $checksum = 256; for ($i = 0; $i < 148; $i++) { $checksum += ord($header[$i]); } for ($i = 156; $i < 512; $i++) { $checksum += ord($header[$i]); } if ($current['checksum'] != $checksum) { break; } $size = ceil($current['size'] / 512); $current['data'] = substr($data, ++$offset << 9, $current['size']); $offset += $size; // Not a directory and doesn't exist already... if (substr($current['filename'], -1, 1) != '/' && !file_exists($destination . '/' . $current['filename'])) { $write_this = true; } elseif (substr($current['filename'], -1, 1) != '/') { $write_this = $overwrite || filemtime($destination . '/' . $current['filename']) < $current['mtime']; } elseif ($destination !== null && !$single_file) { // Protect from accidental parent directory writing... $current['filename'] = strtr($current['filename'], array('../' => '', '/..' => '')); if (!file_exists($destination . '/' . $current['filename'])) { mktree($destination . '/' . $current['filename'], 0777); } $write_this = false; } else { $write_this = false; } if ($write_this && $destination !== null) { if (strpos($current['filename'], '/') !== false && !$single_file) { mktree($destination . '/' . dirname($current['filename']), 0777); } // Is this the file we're looking for? if ($single_file && ($destination == $current['filename'] || $destination == '*/' . basename($current['filename']))) { return $current['data']; } elseif ($single_file) { continue; } elseif ($files_to_extract !== null && !in_array($current['filename'], $files_to_extract)) { continue; } package_put_contents($destination . '/' . $current['filename'], $current['data']); } if (substr($current['filename'], -1, 1) != '/') { $return[] = array('filename' => $current['filename'], 'md5' => md5($current['data']), 'preview' => substr($current['data'], 0, 100), 'size' => $current['size'], 'skipped' => false); } } if ($destination !== null && !$single_file) { package_flush_cache(); } if ($single_file) { return false; } else { return $return; } }
function GamesAdminInstall() { global $scripturl, $txt, $smcFunc, $arcSettings, $context, $sourcedir, $boarddir; // Make list of files to be installed if (isset($_REQUEST['file']) || isset($_REQUEST['directory'])) { // We don't want to install games more than once $installed = array(); $result = $smcFunc['db_query']('', ' SELECT game_file FROM {db_prefix}arcade_games', array()); while ($file = $smcFunc['db_fetch_assoc']($result)) { $installed[$file['game_file']] = true; } $smcFunc['db_free_result']($result); // We need write permission to games directory if (!is_writable($arcSettings['gamesDirectory'])) { fatal_lang_error('arcade_not_writable', false, array($arcSettings['gamesDirectory'])); } // We will need this to extract files require_once $sourcedir . '/Subs-Package.php'; // One file if (isset($_REQUEST['file']) && !is_array($_REQUEST['file'])) { $files = array($_REQUEST['file']); } elseif (isset($_REQUEST['file']) && is_array($_REQUEST['file'])) { $files =& $_REQUEST['file']; } else { $files = array(); } // Remove invalid games foreach ($files as $key => $value) { if (!file_exists($arcSettings['gamesDirectory'] . '/' . $value)) { unset($files[$key]); } } // Files from directories if (isset($_REQUEST['directory']) && is_array($_REQUEST['directory'])) { chdir($arcSettings['gamesDirectory']); foreach ($_REQUEST['directory'] as $directory) { $files = array_merge($files, glob($directory . '/*.swf')); } } if (count($files) == 0) { fatal_lang_error('arcade_no_files_selected'); } $games = array(); // Let's make array with basic settings foreach ($files as $file) { $path = $file; $file = basename($file); $dot = strrpos($file, '.'); if ($dot !== false) { $internal_name = substr($file, 0, $dot); } else { fatal_lang_error('arcade_invalid_file', false, array($path)); } if (substr($file, -3) == 'swf') { // Is it already installed? if (isset($installed[$file])) { continue; } $name = str_replace('_', ' ', $internal_name); $games[$internal_name] = array('internal_name' => $internal_name, 'name' => ucwords($name), 'path' => $path, 'file' => $file, 'type' => substr($file, -3)); } elseif (substr($file, -3) == 'zip') { $data = file_get_contents($arcSettings['gamesDirectory'] . $path); if ($data === false) { continue; } // Unable to read file :( $destination = $arcSettings['gamesDirectory'] . $internal_name . '/'; $ret = read_zip_data($data, $destination); unset($data); unlink($arcSettings['gamesDirectory'] . $file); $folder = $internal_name; if ($ret == false) { continue; } // Files that were extracted foreach ($ret as $file_pack) { $basename = basename($file_pack['filename']); // Is it already installed? if (isset($installed[$basename])) { continue; } $path = $folder . '/' . $basename; $dot = strpos($file_pack['filename'], '.'); if ($dot !== false) { $internal_name = substr($basename, 0, $dot); } else { fatal_lang_error('arcade_invalid_file', false, array($path)); } if (substr($basename, -3) == 'swf') { $name = str_replace('_', ' ', $internal_name); $games[$internal_name] = array('internal_name' => $internal_name, 'name' => ucwords($name), 'path' => $path, 'file' => $basename, 'type' => substr($file_pack['filename'], -3)); } } } } // There were packages with errors or no games... if (count($games) == 0) { fatal_lang_error('arcade_no_files_selected'); } // Session will store data $_SESSION['install'] = array('to_check' => $games, 'games' => array(), 'done' => 0, 'total' => count($files), 'begin' => time(), 'end' => 0); redirectexit('action=admin;area=managearcade;sa=files;do=stageone'); } elseif (isset($_SESSION['install'])) { //use getid...it works!! require_once $boarddir . '/getid3/getid3.php'; $install =& $_SESSION['install']; $context['arcade']['install'] = array(); // Games that needs to be checked foreach ($install['to_check'] as $key => $file) { //we need meta-data such as width and height $swf = new getID3(); $swf->analyze($arcSettings['gamesDirectory'] . $file['path']); $file['width'] = $swf->info['video']['resolution_x']; $file['height'] = $swf->info['video']['resolution_y']; $file['bgcolor'] = $swf->info['swf']['bgcolor']; // Change working directory and try to find thumbails $directory = substr($file['path'], 0, strrpos($file['path'], '/')); chdir($arcSettings['gamesDirectory'] . $directory); $thumbnail = glob($file['internal_name'] . '.{png,gif,jpg}', GLOB_BRACE); if (!$thumbnail) { $thumbnail = glob($file['internal_name'] . '1.{png,gif,jpg}', GLOB_BRACE); } // Build array $context['arcade']['install'][] = array('game_name' => $file['name'], 'internal_name' => $file['internal_name'], 'directory' => $directory, 'file' => $file['file'], 'thumbnail' => isset($thumbnail[0]) ? $thumbnail[0] : '', 'score_type' => 0, 'width' => isset($file['width']) ? $file['width'] : '400', 'height' => isset($file['height']) ? $file['height'] : '300', 'bgcolor' => $file['bgcolor']); } $_SESSION['install2'] = $context['arcade']['install']; $context['arcade']['categories'] = prepareCategories(); // Template $context['page_title'] = $txt['arcade_title_install_games']; $context['sub_template'] = 'games_install'; } else { fatal_lang_error('arcade_no_files_selected'); } }