We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 3632
    • 22 Posts
    I want write a snippet/plugin which I can place in a resource with no template that will take a file path passed to it in a GET parameter and force the browser to download that file rather than render it - will be used for PDF’s, JPEG’s and other files that the browser would normally try to display.

    The issue I am having is that because my snippet is running inside a resource it generates ’headers already sent’ errors becaue of the headers already sent by ModX. Because the snippet needs to handle various file types both the content-disposition and content-type headers need to be set dynamically as well as some others for file size etc.

    So my question is, can I dymanically change the headers output by ModX and if so, can anyone point me at some docs that would be useful in doing so?
    • Why not use Static Resources for this? There is no need to write this kind of Snippet since MODX handles this natively using Content Type and Content Disposition data. You also can’t cache the data, protect it, or generate URLs easily for the files this way. Why not just have a script outside of MODX do this?
        • 3632
        • 22 Posts
        I could do that of course but it would have been handy to do in ModX for reuse as I wouldn’t have to reset paths on every deployment - could use $modx->getOption(’base_path’) plus tweak the code through the manager. Seems a common enough task people would have to address and figured there might be a way to access the headers via the API.

        I suppose to get the base_path I can instantiate $modx in my script which will make it more portable.
        • Wouldn’t even need to instantiate $modx, just include the config.inc.php file and use the MODX_BASE_PATH comstant.

          Just wondering; wouldnt the filelister addon help you out?
            Mark Hamstra • Developer spending his days working on Premium Extras and a MODX Site Dashboard with the ability to remotely upgrade MODX and extras to make the MODX world a little better.

            Tweet me @mark_hamstra, check my infrequent blog at markhamstra.com, my slightly more frequent ramblings at MODX.today or see code at Github.
            • 3632
            • 22 Posts
            You can do what I wanted via a plugin called on the onPageInit system event - could tighten it up to restrict it to the download document you you assign for it:

            <?php
            $eventName = $modx->event->name;
            switch($eventName) {
                case 'OnWebPageInit':
            if(!empty($_GET['f'])){
            $file = $modx->getOption('base_path').$_GET['f'];
            if(!file_exists($file)){
                $modx->sendErrorPage();
            }
            if(ini_get('zlib.output_compression')){
                ini_set('zlib.output_compression', 'Off');
            }
            $file_extension = strtolower(substr(strrchr($file,"."),1));
            switch( $file_extension ){
              	case "pdf": $ctype="application/pdf"; break;
              	case "exe": $ctype="application/octet-stream"; break;
              	case "zip": $ctype="application/zip"; break;
              	case "doc": $ctype="application/msword"; break;
              	case "xls": $ctype="application/vnd.ms-excel"; break;
              	case "ppt": $ctype="application/vnd.ms-powerpoint"; break;
              	case "gif": $ctype="image/gif"; break;
              	case "png": $ctype="image/png"; break;
              	case "jpeg":
              	case "jpg": $ctype="image/jpg"; break;
            	case "scr": $ctype="application/octet-stream"; break;
            	case 'kml': $ctype='application/vnd.google-earth.kml+xml';break;
              	default: $ctype="application/force-download";
            }
            header("Pragma: public"); // required
            header("Expires: 0");
            header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
            header("Cache-Control: private",false); // required for certain browsers 
            header("Content-Type: $ctype");
            header("Content-Disposition: attachment; filename=\"".basename($file)."\";" );
            header("Content-Transfer-Encoding: binary");
            header("Content-Length: ".filesize($file));
            readfile("$file");
            exit();
            };
            break;
            }
            


            Though I don’t need it in this particular case, its worth noting that I could utilise authentication here to restrict download access or use a custom table to log downloads.
              • 3632
              • 22 Posts
              Didn’t know about filelister but will check it out - thanks Mark.
              • Quote from: Mark at Aug 18, 2011, 03:51 PM

                Wouldn’t even need to instantiate $modx, just include the config.inc.php file and use the MODX_BASE_PATH comstant.
                I do not recommend including the MODX config file manually, ever. It could contain constants and other dependencies on xPDO/modX already being included, and this will not be supported moving forward.