Not signed in (Sign In)

Vanilla 1.1.10 is a product of Lussumo. More Information: Documentation, Community Support.

    • CommentAuthorebourg
    • CommentTimeMay 7th 2007
     
    Downloading a large set of pictures often results in a memory allocation error :

    Allowed memory size of <n> bytes exhausted (tried to allocate <m> bytes)

    The cause is the way the zip file is generated, the file is build in memory before being sent to the browser. This generally fails on shared hostings where the memory available is restricted.

    I changed plog-download.php to send the compressed file directly to the browser, the modified file is attached to this post.

    Enjoy,

    Emmanuel Bourg
    • CommentAuthorebourg
    • CommentTimeMay 7th 2007
     
    File attachments are broken, here is the modified plog-download.php file :


    <?php

    include_once("plog-functions.php");

    class zipfile
    {

    var $datasec = array(); // array to store compressed data
    var $ctrl_dir = array(); // central directory
    var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00"; //end of Central directory record
    var $old_offset = 0;
    var $offset = 0;

    /**
    * Add a file to the archive. The compressed file is sent directly to the
    * standard output, the index of the archive is build in memory
    *
    * $data - file contents
    * $name - name of file in archive. Add path if your want
    */
    function add_file($data, $name)
    {
    $name = str_replace("\\", "/", $name);

    $fr = "\x50\x4b\x03\x04";
    $fr .= "\x14\x00"; // ver needed to extract
    $fr .= "\x00\x00"; // gen purpose bit flag
    $fr .= "\x08\x00"; // compression method
    $fr .= "\x00\x00\x00\x00"; // last mod time and date

    $unc_len = strlen($data);
    $crc = crc32($data);
    $zdata = gzcompress($data);
    $zdata = substr( substr($zdata, 0, strlen($zdata) - 4), 2); // fix crc bug
    $c_len = strlen($zdata);
    $fr .= pack("V",$crc); // crc32
    $fr .= pack("V",$c_len); //compressed filesize
    $fr .= pack("V",$unc_len); //uncompressed filesize
    $fr .= pack("v", strlen($name) ); //length of filename
    $fr .= pack("v", 0 ); //extra field length
    $fr .= $name;
    // end of "local file header" segment

    // "file data" segment
    $fr .= $zdata;

    // "data descriptor" segment (optional but necessary if archive is not served as file)
    $fr .= pack("V",$crc); //crc32
    $fr .= pack("V",$c_len); //compressed filesize
    $fr .= pack("V",$unc_len); //uncompressed filesize

    // add this entry to array
    //$this -> datasec[] = $fr;
    echo $fr;
    ob_flush();
    flush();

    $this -> offset += strlen($fr);
    $new_offset = $this -> offset;

    // now add to central directory record
    $cdrec = "\x50\x4b\x01\x02";
    $cdrec .="\x00\x00"; // version made by
    $cdrec .="\x14\x00"; // version needed to extract
    $cdrec .="\x00\x00"; // gen purpose bit flag
    $cdrec .="\x08\x00"; // compression method
    $cdrec .="\x00\x00\x00\x00"; // last mod time & date
    $cdrec .= pack("V",$crc); // crc32
    $cdrec .= pack("V",$c_len); //compressed filesize
    $cdrec .= pack("V",$unc_len); //uncompressed filesize
    $cdrec .= pack("v", strlen($name) ); //length of filename
    $cdrec .= pack("v", 0 ); //extra field length
    $cdrec .= pack("v", 0 ); //file comment length
    $cdrec .= pack("v", 0 ); //disk number start
    $cdrec .= pack("v", 0 ); //internal file attributes
    $cdrec .= pack("V", 32 ); //external file attributes - 'archive' bit set

    $cdrec .= pack("V", $this -> old_offset ); //relative offset of local header
    $this -> old_offset = $new_offset;

    $cdrec .= $name;
    // optional extra field, file comment goes here
    // save to central directory
    $this -> ctrl_dir[] = $cdrec;
    }

    function file() { // dump out file
    $data = implode("", $this -> datasec);
    $ctrldir = implode("", $this -> ctrl_dir);

    return
    $data.
    $ctrldir.
    $this -> eof_ctrl_dir.
    pack("v", sizeof($this -> ctrl_dir)). // total # of entries "on this disk"
    pack("v", sizeof($this -> ctrl_dir)). // total # of entries overall
    pack("V", strlen($ctrldir)). // size of central dir
    pack("V", $this->offset). // offset to start of central dir
    "\x00\x00"; // .zip file comment length
    }
    }

    include("plog-globals.php");


    if (!isset($_REQUEST["checked"]) || (!is_array($_REQUEST["checked"]))){
    echo 'No pictures were selected.';
    } else{
    create_zip($_REQUEST["checked"], $_REQUEST["dl_type"]);
    }

    function create_zip($checked, $level){
    global $zipfile;

    $dir = "Plogger.".date("Y.m.d")."/";

    $zipfile = new zipfile();

    // the next three lines force an immediate download of the zip file:
    header("Content-type: application/octet-stream");
    header("Content-disposition: attachment; filename=photos-".date("Y.m.d").".zip");
    add_photos($checked, $level, $dir, $zipfile);
    echo $zipfile -> file();

    ob_flush();
    flush();

    return;
    }
    • CommentAuthorebourg
    • CommentTimeMay 7th 2007
     
    Second part of the file :

    function add_photos($checked, $type, $dir){
    global $TABLE_PREFIX;
    global $zipfile;

    if ($type == "collections"){
    foreach ($checked as $cid){
    $query = "SELECT * FROM `".$TABLE_PREFIX."collections` WHERE `id`='".$cid."'";
    $result = run_query($query);

    while ($row = mysql_fetch_assoc($result)){
    $query = "SELECT * FROM `".$TABLE_PREFIX."albums` WHERE `parent_id`='".$row["id"]."'";
    $newresult = run_query($query);

    $newchecked = array();

    while ($newrow = mysql_fetch_assoc($newresult)){
    $newchecked[] = $newrow["id"];
    }

    $newdir = $row["name"];

    $i = 1;

    while (is_dir($newdir)){
    $newdir = $row["name"] . " (".$i++.")";
    }

    // $zipfile -> add_dir($dir . $newdir);

    add_photos($newchecked, "albums", $dir . $newdir . "/");
    }
    }
    }
    elseif($type == "albums"){
    foreach ($checked as $aid){
    $query = "SELECT * FROM `".$TABLE_PREFIX."albums` WHERE `id`='".$aid."'";
    $result = run_query($query);

    while ($row = mysql_fetch_assoc($result)){
    $query = "SELECT * FROM `".$TABLE_PREFIX."pictures` WHERE `parent_album`='".$row["id"]."'";
    $newresult = run_query($query);

    $newchecked = array();

    while ($newrow = mysql_fetch_assoc($newresult)){
    $newchecked[] = $newrow["id"];
    }

    $newdir = $row["name"];

    $i = 1;

    while (is_dir($newdir)){
    $newdir = $row["name"] . " (".$i++.")";
    }


    // $zipfile -> add_dir($dir . $newdir);

    add_photos($newchecked, "pictures", $dir . $newdir . "/");
    }
    }
    }
    elseif($type == "pictures"){
    foreach ($checked as $pid){
    $query = "SELECT * FROM `".$TABLE_PREFIX."pictures` WHERE `id`='".$pid."'";
    $result = run_query($query);

    while ($row = mysql_fetch_assoc($result)){
    $file_contents = file_get_contents("images/".$row["path"], true);
    $zipfile -> add_file($file_contents, $row["path"]);

    }
    }
    }

    return;
    }

    ?>
    • CommentAuthordurex
    • CommentTimeJul 23rd 2008
     
    Hi there, this is working, but the zip file is way to small after the download and it`s says that the file is corrupt or not a zip file. Is this a bug, or just me having this problem?
    Hope you can answer (PS sorry for my bad English)