Zip Download ZIP Changes Folder Name of Wordpress

2019-08-13 11:57发布

I've been trying to solve this but can't seem to find anything on it.

When you "Download ZIP" from github, it doesn't give you the "theme_name.zip" that you'd hope for, but rather "theme_name-master.zip", which when average users install this the messed up folder name throws off child themes.

How can this be remedied, so that the zip download does not change anything?

2条回答
孤傲高冷的网名
2楼-- · 2019-08-13 12:11

That's a bit problematic and I don't think there's a real fix, only workarounds. I faced the same problem with plugins and have only a partial solution: it works only on plugin/theme updates, not when installing.

Never tried, but maybe it's possible to perform the folder rename on plugin (register_activation_hook) or theme (after_switch_theme) activation.

I've checked the core and the filter upgrader_source_selection works for themes and plugins. The repo slug is in GitHub's URL: http://github.com/user/repo-name.

public static $repo_slug = 'repo-name';

add_filter( 'upgrader_source_selection', array( $this, 'rename_github_zip' ), 1, 3 );

/**
 * Removes the prefix "-master" when updating from GitHub zip files
 * 
 * See: https://github.com/YahnisElsts/plugin-update-checker/issues/1
 * 
 * @param string $source
 * @param string $remote_source
 * @param object $thiz
 * @return string
 */
public function rename_github_zip( $source, $remote_source, $thiz )
{
    if(  strpos( $source, self::$repo_slug ) === false )
        return $source;

    $path_parts = pathinfo($source);
    $newsource = trailingslashit($path_parts['dirname']). trailingslashit( self::$repo_slug );
    rename($source, $newsource);
    return $newsource;
}
查看更多
唯我独甜
3楼-- · 2019-08-13 12:23

For simplicity, You could host a script somewhere that downloads the script, renames the folder without the -master and then rezip's the project, then send it to the user as a download.

So something like (Requires PHP5 >= 5.2.0, cURL, ZipArchive, safe_mode & open_basedir off):

Fork it from GitHub ;p

<?php
//Example Usage
new GitDL('https://github.com/lcherone/GitDL');

/**
 * GitHub Project/Repository Downloader proxy.
 * This class will handle downloading, removing master folder prefix, 
 * repacking and proxying back the project as a download.
 * 
 * @author Lawrence Cherone
 * @version 0.2
 */
class GitDL{
    // project files working directory - automatically created
    const PWD = "./project_files/";

    /**
     * Class construct.
     *
     * @param string $url
     */
    function __construct($url=null){
        // check construct argument
        if(!$url) die('Class Error: Missing construct argument: $url');

        // fix trailing slash if any
        $url = rtrim($url, '/');

        // assign class properties
        $this->project     = basename($url);
        $this->project_url = $url.'/archive/master.zip';
        $this->tmp_file    = md5($url).'.zip';

        // make project working folder
        if(!file_exists(self::PWD)){
            mkdir(self::PWD.md5($url), 0775, true);
        }

        // get project zip from GitHub
        try{
            $this->get_project();
        }catch(Exception $e){
            die($e->getMessage());
        }

        // extract project zip from git
        $this->extract(self::PWD.$this->tmp_file, self::PWD.md5($url));

        // remove the master part, by renaming
        rename(self::PWD.md5($url).'/'.$this->project.'-master', self::PWD.md5($url).'/'.$this->project);

        // rezip project files
        $this->zipcreate(self::PWD.md5($url), self::PWD.'new_'.$this->tmp_file);

        // send zip to user
        header('Content-Description: File Transfer');
        header('Content-Type: application/zip');
        header('Content-Disposition: attachment; filename="'.$this->project.'.zip"');
        header('Content-Transfer-Encoding: binary');
        header('Expires: 0');
        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        header('Pragma: public');
        header('Content-Length: '.sprintf("%u", filesize(self::PWD.'new_'.$this->tmp_file)));
        readfile(self::PWD.'new_'.$this->tmp_file);

        // cleanup
        $this->destroy_dir(self::PWD.md5($url));
        unlink(self::PWD.$this->tmp_file);
        unlink(self::PWD.'new_'.$this->tmp_file);
    }

    /**
     * cURL GitHub project downloader. 
     * No support for open base dir/safe mode as there is a GitHub redirect to there CDN
     * a HEAD pre-check is done to check project exists,
     * project zip is written directly to the file.
     */
    function get_project(){
        // check curl installed
        if(!function_exists('curl_init')){
            throw new Exception('cURL Error: You must have cURL installed to use this class.');
        }
        // check for unsupported settings
        if (ini_get('open_basedir') != '' || ini_get('safe_mode') == 'On'){
            throw new Exception('cURL Error: safe_mode or an open_basedir is enabled, class not supported.');
        }

        // HEAD request - To verify the project exists
        $ch = curl_init();
        curl_setopt_array($ch, array(
            CURLOPT_URL => $this->project_url,
            CURLOPT_TIMEOUT => 5,
            CURLOPT_CONNECTTIMEOUT => 5,
            CURLOPT_FAILONERROR => true,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_BINARYTRANSFER => true,
            CURLOPT_HEADER => false,
            CURLOPT_NOBODY => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_SSL_VERIFYPEER => false,
        ));

        // lets grab it
        if(curl_exec($ch) !== false){
            $fp = fopen(self::PWD.$this->tmp_file, 'a+b');
            if(flock($fp, LOCK_EX | LOCK_NB)){
                // empty possible contents
                ftruncate($fp, 0);
                rewind($fp);

                // HTTP GET request - write directly to the file
                $ch = curl_init();
                curl_setopt_array($ch, array(
                    CURLOPT_URL => $this->project_url,
                    CURLOPT_TIMEOUT => 5,
                    CURLOPT_CONNECTTIMEOUT => 5,
                    CURLOPT_FAILONERROR => true,
                    CURLOPT_RETURNTRANSFER => true,
                    CURLOPT_BINARYTRANSFER => true,
                    CURLOPT_HEADER => false,
                    CURLOPT_FILE => $fp,
                    CURLOPT_FOLLOWLOCATION => true,
                    CURLOPT_SSL_VERIFYHOST => false,
                    CURLOPT_SSL_VERIFYPEER => false,
                ));

                // transfer failed
                if(curl_exec($ch) === false){
                    ftruncate($fp, 0);
                    throw new Exception('cURL Error: transfer failed.');
                }
                fflush($fp);
                flock($fp, LOCK_UN);
                curl_close($ch);
            }
            fclose($fp);
        }else{
            curl_close($ch);
            throw new Exception('Error: '.htmlentities($this->project).' project not found on GitHub');
        }
    }

    /**
     * Create zip from extracted/fixed project.
     *
     * @uses ZipArchive
     * @uses RecursiveIteratorIterator
     * @param string $source
     * @param string $destination
     * @return bool
     */
    function zipcreate($source, $destination) {
        if (!extension_loaded('zip') || !file_exists($source)) {
            return false;
        }
        $zip = new ZipArchive();
        if (!$zip->open($destination, ZIPARCHIVE::CREATE)) {
            return false;
        }
        $source = str_replace('\\', '/', realpath($source));
        if (is_dir($source) === true) {
            $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);
            foreach ($files as $file) {
                $file = str_replace('\\', '/', realpath($file));
                if (is_dir($file) === true) {
                    $zip->addEmptyDir(str_replace($source.'/', '', $file.'/'));
                } else if (is_file($file) === true) {
                    $zip->addFromString(str_replace($source.'/', '', $file), file_get_contents($file));
                }
            }
        }
        return $zip->close();
    }

    /**
     * Extract Zip file
     *
     * @uses ZipArchive
     * @param string $source
     * @param string $destination
     * @return bool
     */
    function extract($source, $destination){
        $zip = new ZipArchive;
        if($zip->open($source) === TRUE) {
            $zip->extractTo($destination);
            $zip->close();
            return true;
        } else {
            return false;
        }
    }

    /**
     * Recursive directory remover/deleter
     *
     * @uses RecursiveIteratorIterator
     * @param string $dir
     * @return bool
     */
    function destroy_dir($dir) {
        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);
    }

}
?>
查看更多
登录 后发表回答