Example #1
0
/**
 * 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);
    }
}
Example #2
0
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;
    }
}
Example #3
0
/**
 * 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;
    }
}
Example #4
0
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');
    }
}