Forums

The forums ran from 2008-2020 and are now closed and viewable here as an archive.

Home Forums Back End php download multiple files problem.

  • This topic is empty.
Viewing 9 posts - 31 through 39 (of 39 total)
  • Author
    Posts
  • #185222
    TC
    Participant

    Hi __.

    I’m still having a bear of a time trying to get this to work.

    Now that you know what the difference between GET and POST is, can you see which method goes with each approach?

    Yes and once again thank you for your explanations and help :)
    I have never before in my life been stuck like this for so long on any problem and still not be able to succeed or understand what I’m doing wrong.
    I can’t believe nobody has written a book exactly explaining what I’m trying to do.
    It should be simple: Select images from a gallery and then click a button to zip and download them. Trying this by trial and error and searching all over the net is insane.
    I don’t know if you ever want to write a book on web development but if so you should consider writing a book about real world web development needs like I’m struggling with. I’m sure thousands of developers would love it. People would buy it just to save themselves the misery and lost time of having to search endlessly on the internet and then go through the trial and error process.

    OK this is my latest failed attempt:
    One gallery page with the calling javascript which correctly (verified) sends the filenames via $_GET to the php page which correctly zips all of the images but still fails to download them. I’ve tried adding the iframe example you showed me and I’ve failed. I’ve also tried adding another iframe example from S.O. and failed.

    The goal here is to have one javascript gallery page and one php page which does both the zipping and the download.

    I don’t seem to be correctly calling the iframed function to do the download.

    Can you PLEASE fix my script so it calls the iframe function to perform the download after the file was successfully zipped? See the php line :
    if (create_zip($files_actual,$zipfile)); // array of filenames to zip, full path to zip file.
    {
    // here I try to call the javascript iframe function to do the download but I fail.
    }
    <code></code>

    I have a lot of commented out junk in my code because I keep trying and keep failing.
    On as usual if I load the script directly in the browser it correctly downloads the images.zip file.
    It’s only if I try to call it from javascript that it does not download.

    Somehow I messed up my code so now the zip file isn’t being created correctly.

    I will fix that then post the script :)

    #185228
    TC
    Participant

    Ok this is the code that zips the files correctly but does not download the images.zip file if javascript calls it.
    If I load it in via browser it does download the images.zip file.

    
    <?php
    // ob_start();
    
    // If called from the javascript gallery page this script correctly zips the images.zip file. so we know the $GET is working.
    // Not working: Still does not do the download when called from the javascript gallery page.
    // I don't seem to be executing the Javascript download function after the zip file is created and verified to exist.
    // how do I do this?
    
    // If I execute this page in the URL of the browser it does correctly download the images.zip file.
    
    /* put this script on your server. in the same directory, create a new directory named "downloads". 
    put any files you wish to be available for download in the downloads/ directory.
    (if you wish to put downloads somewhere else, change the value of the DOWNLOAD_DIRECTORY constant below.)
    navigate to this page from the web and enter the filename (including file extension) of the file you wish to download.
    */
    // change as needed.  Users will be allowed to download ALL files in this directory.
    // KEEP TRAILING SLASH.
     define( "DOWNLOAD_DIRECTORY",realpath("./downloads")."/" );
    
    // if there is a request for a file, and it is a downloadable file
    /*
    if( isset( $_GET['file'] ) && validate_download_request( DOWNLOAD_DIRECTORY,$_GET['file'] ) ){
        // download it and exit
        download_file( DOWNLOAD_DIRECTORY,$_GET['file'] );
        exit;
    }
    */
    
     if (isset($_GET['files'])) { $temp_files=($_GET['files']); }
    
    // json_encode($temp_files);
    utf8_encode($temp_files);
    
    // path to where the images are, leave the trailing '/'
    $path="/path/to/image-gallery/"; // CHANGE TO INTERNAL SERVER PATH OF THE IMAGES GALLERY.
    
    $files_actual=array();
    $files_list=explode(",",$temp_files); // now we have our array.
    
    foreach($files_list as $tempfile) // now prepend the path to each filename.
    { array_push($files_actual,$path.$tempfile);  }
    
    $zipfile="./downloads/images.zip"; // pass entire path to create_zip ().
    $file="images.zip"; // pass only filename to download_file ()
    
    if (create_zip($files_actual,$zipfile)); // array of filenames to zip, full path to zip file.
    {  // Zip was successfully created so download it now.
    $file="images.zip"; // pass only filename to download_file ()
    
    download_file( DOWNLOAD_DIRECTORY,$file );
    
    // below are many failed attempts to call the javascript iframe function which should perform the download.
    // Here I need to execute the javascript function in the iframe to perform the download.
    //  download_file(DOWNLOAD_DIRECTORY, $file);  // does not work.
     //makeFrame($zipfile); // tried another iframe download does not work.
     
     /*
     if( isset( $_GET['files'] ) && validate_download_request( DOWNLOAD_DIRECTORY,$file ) )
     {
        // download it and exit
        download_file( DOWNLOAD_DIRECTORY,$file );
        exit;
     }
     */
     
      // try to execute the javascript the below way, does not work:
    //echo '<script type="text/javascript">'
      // , 'makeFrame($zipfile);'
       //, '</script>';
    
     
    // try to execute the javascript the below way, does not work:
    //echo '<script type="text/javascript">'
    //   , 'download_file("./downloads/", "images.zip")'
    //   , '</script>';
    
    } 
    
    ////////////////////zip function code:
    function create_zip($files = array(),$destination = '',$overwrite = true) {
        //if the zip file already exists and overwrite is false, return false
        if(file_exists($destination) && !$overwrite) { return false; }
        //vars
        $valid_files = array();
        //if files were passed in...
        if(is_array($files)) {
            //cycle through each file
            foreach($files as $file) {
                //make sure the file exists
                if(file_exists($file)) {
                    $valid_files[] = $file;
                }
            }
        }
        //if we have good files...
        if(count($valid_files)) {
            //create the archive
            $zip = new ZipArchive();
            if($zip->open($destination,$overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true) {
                return false;
            }
            //add the files
            foreach($valid_files as $file) {
                $zip->addFile($file,basename($file));
            }
            //debug
            //echo 'The zip archive contains ',$zip->numFiles,' files with a status of ',$zip->status;
            
            //close the zip -- done!
            $zip->close();
            
            //check to make sure the file exists
            return file_exists($destination);
        }
        else
        {
            return false;
        }
            
    } ///// END of the create zip function.
    
    //////////////////////////////////////END MY ZIP CODE.
    
    ///////////BEGIN ___ code that works to download.
    
     // $file="images.zip";
    //   download_file(DOWNLOAD_DIRECTORY, $file);
    
    // otherwise, we keep going and the html page will be output.
    // function definitions:
    // ~~~~~~~~~~~~~~~~~~~~~
    /**
     * makes sure the requested file exists in the download directory.
     *
     * @param string $dir   absolute filesystem path to the download directory
     * @param string $file  name of the file to check (may be in a sub-directory)
     * @return bool         TRUE if file exists in the download directory, 
     *                      FALSE otherwise
     */
    function validate_download_request( $dir,$file )   {
        return (realpath( $dir.$file ) === $dir.$file);}
     
     
     //////////////////try a different download function.
    /** adds necessary HTTP headers and reads the specified file as a download.
     * @param string $dir   absolute filesystem path to the download directory
     * @param string $file  the file to download
     */
     
    function download_file( $dir,$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( $dir.$file ) );
        readfile( $dir.$file );
    }
    ////////////////////////End ___ downoad function.
    
    /* couldnt get this to work either.
    
    function makeFrame( $url ) 
    { 
        ifrm = document.createElement( "IFRAME" ); 
        ifrm.setAttribute( "style", "display:none;" ) ;
        ifrm.setAttribute( "src", url ) ; 
        ifrm.style.width = 0+"px"; 
        ifrm.style.height = 0+"px"; 
        document.body.appendChild( ifrm ) ; 
    }  
    
    function downloadChecked( )
    {
        for( i = 0 ; i < document.downloadform.elements.length ; i++ )
        {
            foo = document.downloadform.elements[ i ] ;
            if( foo.type == "checkbox" && foo.checked == true )
            {
                makeFrame('somefile.do?command=download&fileid=' + foo.name );
            }
        }
    }
    
    */
    // ob_end_flush();
    // html markup
    
    ?>
    
    <!doctype html>
    <html>
        <head>
            <meta charset=utf-8>
            <title>file download demo</title>
        </head>
        <body>
            <label>
                Type the name of the file you wish to download: 
                <input id=filename>
            </label>
            <button id=download>download file</button>
            
            
            
            <script>
    (function(){
            // reference the #filename input element
        // var filename = document.getElementById('filename'),
           var filename = "images.zip",
            // reference the #download button element
            download = document.getElementById('download'),
            // the url to request the download from (blank here, because it is all one page)
            url = '',
            // event handler for when the #download button is clicked
            download_onClick = function( event ){
                    // create an iframe to trigger the download
                var downloadTarget = document.createElement('iframe');
                // set the iframe src to the url and add the requested filename to the query string
                downloadTarget.src = url + '?file='+encodeURIComponent( filename.value );
                // make sure the iframe is not visible
                downloadTarget.setAttribute( 'style','visibility:hidden;display:none;' );
                // add the iframe to the document (this is what actually triggers the download)
                document.body.appendChild( downloadTarget );
            };
        // attach the event handler to the #download button and wait for clicks
        download.addEventListener( 'click',download_onClick );
    })()
    
    //////// END ___ code which does the download if we load the page in the browser but not by calling it with javascript.
            </script>
            
            
            
        </body>
    </html>
    
    
    #185245
    __
    Participant

    okay… it looks like you’ve put together parts of several scripts. Also like you’re writing js functions, but in the PHP portion of your script. Let me look at this and I’ll see what I can get working.

    #185265
    TC
    Participant

    That would be fantastic __!

    I was trying to combine what I learned from you, what I picked up elsewhere on the net and what I learned before reading.

    Wow, this problem spun my head around and washed away a lot of what I learned.

    I decided to take a break from this problem and work on another problem of emailing an attachment. Luckily I got that working in a single day! :)

    So many email attachment scripts on the net don’t work. I don’t know why the authors put them up? Maybe they are trying to mess people up to protect their jobs?

    Looking forward to your solution!
    Need to learn more.

    #185266
    __
    Participant

    I just realized that this doesn’t need to be a two-step process. You can pass the filenames in the query string in the iframe’s src and just generate the zip archive on the fly. You could also cache the results to save time on future requests.

    #185290
    TC
    Participant

    Good morning __ :)

    Thank you for helping me on this.

    I just realized that this doesn’t need to be a two-step process. You can pass the filenames in the query string in the iframe’s src and just generate the zip archive on the fly.

    I think that’s what I’m trying to do. I couldn’t get the javascript two step process working so the above script is supposed zip then do your iframe download in one go.

    In this single script I planned on creating the zip file then after confirmation execute the iframe’s download code.
    I think the problem is I don’t know how to call your iframe function from php.
    You have it set up to execute on a button click with HTML. I don’t know how to execute it from php?
    I’m sure you know the download should happen only after the new zip has been created, otherwise it would download the wrong zip file from the previous zip. That’s why I’m trying to execute your javascript iframe download code from within the confirming zip creation statement:

    `
    if (create_zip($files_actual,$zipfile)); // pass array of filenames to zip, full path to zip file.
    {

    // Zip was successfully created so download it now by executing the iframe download code but I don’t know how to do this?
    // Removed my many failed attempts that were in the previous full code post.

    }
    `
    In that code post I omitted my many failed attempts trying to execute your iframe javascript code in the below post. They appear in the full code post in the earlier post but none of them work so the download never happens. There could be other errors too I’m not sure.

    You could also cache the results to save time on future requests.
    I’d like to avoid caching anything just to be safe.

    I thought it would be pretty doable for you to get that single script working ? Much of it is based on your single page example :)

    It should be pretty close, I think if we can call your iframe javascript download from the line I posted it would work unless I goofed up some parameters in your iframe dl code.

    Were getting super close to getting this working I know it!

    Btw, are you a professional? You must do this as your career yes?

    :)

    #185305
    __
    Participant

    I think the problem is I don’t know how to call your iframe function from php.

    It is not possible for javascript and php to interact. They do not work at the same time nor place.

    • PHP happens on the server. At this point, there is no such thing as javascript. As far as PHP is concerned, it is all just text. When PHP is done, it sends its output to the browser, and then shuts down.
    • JS happens on the user’s browser. It has no idea there is even such a thing as PHP. Even if you used PHP to dynamically write part of your JS, at this point, it’s all just js code.

    Your JS and PHP scripts can “communicate” via HTTP requests (e.g., page loads, ajax), but they are still “taking turns” executing and neither is “aware” of the other — just the info they send, and the response they get back.

    I’m sure you know the download should happen only after the new zip has been created, otherwise it would download the wrong zip file …

    No, actually: there only needs to be one request. Once javascript creates the iframe with the desired file names, the browser sends a request to the php script. The php script controls how to respond: it can simply create the zip archive first, and then read it out as an attachment after.

    I started writing this last night but some other work came up. I’ll see if I can finish it today.

    One thing I find useful, and always recommend, is “wireframing” your scripts, just like you might wireframe an html page. Without using code, outline the steps that your script will need to take, and then go back over it, adding more and more detail. At some point, what you need to write will be very clear, and you can just belt out your actual code.

    <?php
    
    if download requested
        get list of filenames
        for each filename:
            if file exists and is allowed to be downloaded
                continue
            if not
                exit 404 Not Found
        create a zip archive and add all files
        if zip archive is successful
            set attachment headers
            set content headers
            read file; exit 200 OK
        if not
            exit 500 Server Error
    if not:
    ?><html>
    …
    
    #185918
    TC
    Participant

    Hi __.

    Yes I often do try to wireframe before I code, thanks for the reminder.

    I started writing this last night but some other work came up. I’ll see if I can finish it today.

    Were you successful or did you get stuck?

    :)

    #185935
    __
    Participant

    I had another project come up that kinda pushed this aside. I promise I’ll get back to it (probably next monday or tuesday). Sorry to leave you hanging.

Viewing 9 posts - 31 through 39 (of 39 total)
  • The forum ‘Back End’ is closed to new topics and replies.