dongque4778
2014-05-15 02:32
浏览 390
已采纳

由ZipArchive生成的PHP动态生成的Zip文件无法打开

I'm trying to create a zip file of user uploaded images that will be generated for download when a user clicks a button. The button is on a page in the Wordpress admin. The page is from a plugin that adds a new admin section. When the button is clicked, it submits a form to a page in 'themes/twentyfourteen/page-templates' directory. The page is called cartoon_zip.php and was created through the Pages section in the admin, so it has the url of http://www.sitename.com/cartoon-zip/. When I click the file, it appears to work. No errors occur, and a save file dialog appears. I save the file locally and try to unzip but get the message 'The contents of the file "characters.zip" can not be extracted with this program.' I'm on a mac, so it's The Unarchiver trying to open; it doesn't work on a PC either though. Below is the code I'm using; any help is greatly appreciated.

<?php 
    /*
        Template name: Cartoon Zip
    */

    if(isset($_REQUEST['order_id'])){
        $order_id = $_REQUEST['order_id'];

        $query = "SELECT optional_image FROM order_listing WHERE order_no = '".$order_id."'";
        $query2 = "SELECT main_image FROM character_order WHERE order_id = '".$order_id."'";

        $entries = $wpdb->get_results($query);
        $entries2 = $wpdb->get_results($query2);

        $error = "";        //error holder

        if(extension_loaded('zip')){    // Checking ZIP extension is available

            $zip = new ZipArchive();            // Load zip library 
            $zip_name = "characters.zip";           // Zip name

            if($zip->open($zip_name, ZIPARCHIVE::CREATE)!==TRUE){       // Opening zip file to load files
                $error .=  "* Sorry ZIP creation failed at this time<br/>";
            }

            foreach( $entries as $entry ) {
                $image=$entry->optional_image; 
                if(!empty($image)):
                    $url = 'wp-content/themes/twentyfourteen/upload/main/'.$image;
                    if(file_exists($url)){
                        $zip->addFile($url,$image);         // Adding files into zip
                    }
                endif;
            }
            foreach( $entries2 as $entry ) {
                $image=$entry->main_image; 
                if(!empty($image)):
                    $url = 'wp-content/themes/twentyfourteen/upload/character/'.$image;
                    if(file_exists($url)){
                        $zip->addFile($url,$image);         // Adding files into zip
                    }
                endif;
            }

            if ($zip->close() === false) {
                exit("Error creating ZIP file");
            };

            $filename = $zip_name;
            // send $filename to browser
            $finfo = finfo_open(FILEINFO_MIME_TYPE);
            $mimeType = finfo_file($finfo, $filename);
            $size = filesize($filename);
            $name = basename($filename);

            if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
                // cache settings for IE6 on HTTPS
                header('Cache-Control: max-age=120');
                header('Pragma: public');
            } else {
                header('Cache-Control: private, max-age=120, must-revalidate');
                header("Pragma: no-cache");
            }
            header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // long ago
            header("Content-Type: $mimeType");
            header('Content-Disposition: attachment; filename="' . $name . '";');
            header("Accept-Ranges: bytes");
            header('Content-Length: ' . filesize($filename));

            readfile($fullFilePath);
            exit;
        }else
            $error .= "* You dont have ZIP extension<br/>";
    }
?>

EDIT: So I manged to get this working with a combination doublesharp's help below and by changing the headers to the following.

$file = $zip_name;
        if (file_exists($file)) {
            header('Content-Description: File Transfer');
            header('Content-Type: application/octet-stream');
            header('Content-Disposition: attachment; filename='.basename($file));
            header('Expires: 0');
            header('Cache-Control: must-revalidate');
            header('Pragma: public');
            header('Content-Length: ' . filesize($file));
            ob_clean();
            flush();
            readfile($file);
            exit;
        }

Here's the full working code.

<?php 
/*
    Template name: Cartoon Zip
*/

if(isset($_REQUEST['order_id'])){
    global $wpdb;
    $order_id = isset( $_REQUEST['order_id'] )? $_REQUEST['order_id'] : 0;

    $query = $wpdb->prepare( "SELECT optional_image FROM order_listing WHERE order_no = %s", $order_id );
    $query2 = $wpdb->prepare( "SELECT main_image FROM character_order WHERE order_id = %s", $order_id );

    $entries = $wpdb->get_results($query);
    $entries2 = $wpdb->get_results($query2);

    $error = "";        //error holder

    if(extension_loaded('zip')){    // Checking ZIP extension is available

        $zip = new ZipArchive();            // Load zip library 
        $zip_name = "characters.zip";           // Zip name

        if($zip->open($zip_name, ZIPARCHIVE::CREATE)!==TRUE){       // Opening zip file to load files
            $error .=  "* Sorry ZIP creation failed at this time<br/>";
        }

        foreach( $entries as $entry ) {
            $image=$entry->optional_image; 
            if( ! empty( $image ) ){
                $filename = WP_CONTENT_DIR.'/themes/twentyfourteen/upload/main/'.$image;
                if ( file_exists( $filename ) ){
                    // Adding files into zip
                    $zip->addFile( $filename, $image );
                }
            }
        }
        foreach( $entries2 as $entry ) {
            $image=$entry->main_image; 
            if( ! empty( $image ) ){
                $filename = WP_CONTENT_DIR.'/themes/twentyfourteen/upload/character/'.$image;
                if ( file_exists( $filename ) ){
                    // Adding files into zip
                    $zip->addFile( $filename, $image );
                }
            }
        }

        if ($zip->close() === false) {
            exit("Error creating ZIP file");
        };

        $file = $zip_name;
        if (file_exists($file)) {
            header('Content-Description: File Transfer');
            header('Content-Type: application/octet-stream');
            header('Content-Disposition: attachment; filename='.basename($file));
            header('Expires: 0');
            header('Cache-Control: must-revalidate');
            header('Pragma: public');
            header('Content-Length: ' . filesize($file));
            ob_clean();
            flush();
            readfile($file);
            exit;
        }
    }else
        $error .= "* You dont have ZIP extension<br/>";
}
?>
  • 写回答
  • 好问题 提建议
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • dou7466 2014-05-15 03:44
    已采纳

    The first argument to addFile() needs to be the full path to the image, but you are using a relative path with wp-content/.... The template for this page is most likely in your wp-content/themes/ directory so the call to file_exists() fails which means that nothing is ever passed to ZipArchive. WordPress provides a constant that contains the absolute path to the wp-content folder called WP_CONTENT_DIR - or if you aren't sure what theme you will be in you can use get_template_directory().

    Using WP_CONTENT_DIR:

    if( ! empty( $image ) ){
        $filename = WP_CONTENT_DIR.'/themes/twentyfourteen/upload/character/'.$image;
        if ( file_exists( $filename ) ){
            // Adding files into zip
            $zip->addFile( $filename, $image );
        }
    }
    

    Using get_template_directory():

    $filename = get_template_directory().'/upload/character/'.$image;
    

    SQL INJECTION WARNING

    You also have a SQL injection vulnerability where it is possible to pass arbitrary SQL in the order_id of the request. Use $wpdb->prepare() to protect against it.

    global $wpdb;
    $order_id = isset( $_REQUEST['order_id'] )? $_REQUEST['order_id'] : 0;
    $query = $wpdb->prepare( "SELECT optional_image FROM order_listing WHERE order_no = %s", $order_id );
    $query2 = $wpdb->prepare( "SELECT main_image FROM character_order WHERE order_id = %s", $order_id );
    
    已采纳该答案
    评论
    解决 无用
    打赏 举报

相关推荐 更多相似问题