MicWit MicWit - 3 years ago 238
Twig Question

Sending TWIG output to a zip in Symfony for Templating

I need to create a system that will be able to output a template (a zip with an index.html with all js, css, img etc files as required) based on a set of options (include menu 1, use small footer etc).

So I can put code blocks in so it would not be hard to actually output to the browser the required look, but what if I want to save the rendered html (and this means we would need to change the locations of files like js etc) to a zip instead?

Any ideas? At the moment I'm thinking it would all need to be processed in PHP anyhow (the controller) and TWIG may not be too helpful, but that would make it more complicated.

Answer Source

So I worked this one out, here is the controller to output the required twig zipped:


namespace AppBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class DefaultController extends Controller
     * @Route("/{variableName}", name="homepage"})
    public function indexAction($variableName = "Default")
        //do whatever you need to get the template correct

        //send rendered TWIG to a variable
        $renderedhtml = $this->render('default/index.html.twig', [
            'variableName' => $variableName

        $zipName = "template.zip";
        $main = $this->get('kernel')->getRootDir() . '/../web/workingdir/';
        $vername = time(); //we use the exact time to get a unique dir name

        //remove any projects older than a few minutes (5 in this case)
        $dirHandle = opendir($main);
        while($item = readdir($dirHandle)){
            if(is_dir($main . $item) && $item != '.' && $item != '..') {
                if ( ( ( $item + ( 60 * 5 ) ) < $vername ) ) {
                    system('/bin/rm -rf ' . escapeshellarg($main . $item));

        //make the project dir and populate it with files (in this case just the template as index.html, you would want to copy all other files here though)
        file_put_contents($main.$vername."/index.html", $renderedhtml);

        //create the zip
        $zip = new \ZipArchive();
        $zip->open($zipName,  \ZipArchive::CREATE);
        $zip = $this->createZip($zip, $main.$vername);

        //get the zip ready to return
        header('Content-Type', 'application/zip');
        header('Content-disposition: attachment; filename="' . $zipName . '"');
        header('Content-Length: ' . filesize($zipName));

    // Create a zip with zip object and root dir params (find and include sub-dirs with content)
    private function createZip($zip, $source) {
        $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('\\', '/', $file);

                if( in_array(substr($file, strrpos($file, '/')+1), array('.', '..')) )

                $file = 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;

Once you get it to this stage, you will just have to add any other required files into the working dir, but I think that could be done under a different issue, this one is about getting the website into a html in a zip.

Hope this helps someone.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download