Completed
Push — master ( 60e303...4c478a )
by
unknown
8s
created

src/Extensions/PdfExportControllerExtension.php (2 issues)

Severity
1
<?php
2
3
namespace CWP\PDFExport\Extensions;
4
5
use SilverStripe\Assets\Filesystem;
6
use SilverStripe\Control\Director;
7
use SilverStripe\Control\HTTPRequest;
8
use SilverStripe\Control\HTTPResponse;
9
use SilverStripe\Core\Config\Config;
10
use SilverStripe\Core\Environment;
11
use SilverStripe\Core\Extension;
12
use SilverStripe\Versioned\Versioned;
13
14
class PdfExportControllerExtension extends Extension
15
{
16
    private static $allowed_actions = [
0 ignored issues
show
The private property $allowed_actions is not used, and could be removed.
Loading history...
17
        'downloadpdf',
18
    ];
19
20
    /**
21
     * Serve the page rendered as PDF.
22
     *
23
     * @return HTTPResponse|false
24
     */
25
    public function downloadpdf()
26
    {
27
        if (!$this->owner->data()->config()->get('pdf_export')) {
28
            return false;
29
        }
30
31
        // We only allow producing live pdf. There is no way to secure the draft files.
32
        Versioned::set_stage(Versioned::LIVE);
33
34
        $path = $this->owner->data()->getPdfFilename();
35
        if (!file_exists($path)) {
36
            $this->owner->generatePDF();
37
        }
38
39
        return HTTPRequest::send_file(file_get_contents($path), basename($path), 'application/pdf');
40
    }
41
42
    /**
43
     * This will return either pdf_base_url from YML, CWP_SECURE_DOMAIN from _ss_environment, or blank. In that
44
     * order of importance.
45
     *
46
     * @return string
47
     */
48
    public function getPDFBaseURL()
49
    {
50
        // if base url YML is defined in YML, use that
51
        if ($this->owner->data()->config()->get('pdf_base_url')) {
52
            $pdfBaseUrl = $this->owner->data()->config()->get('pdf_base_url').'/';
53
            // otherwise, if we are CWP use the secure domain
54
        } elseif (Environment::getEnv('CWP_SECURE_DOMAIN')) {
55
            $pdfBaseUrl = Environment::getEnv('CWP_SECURE_DOMAIN') . '/';
56
            // or if neither, leave blank
57
        } else {
58
            $pdfBaseUrl = '';
59
        }
60
        return $pdfBaseUrl;
61
    }
62
63
    /**
64
     * Don't use the proxy if the pdf domain is the CWP secure domain or if we aren't on a CWP server
65
     *
66
     * @return string
67
     */
68
    public function getPDFProxy($pdfBaseUrl)
69
    {
70
        if (!Environment::getEnv('CWP_SECURE_DOMAIN')
71
            || $pdfBaseUrl == Environment::getEnv('CWP_SECURE_DOMAIN') . '/'
72
        ) {
73
            $proxy = '';
74
        } else {
75
            $proxy = ' --proxy ' . Environment::getEnv('SS_OUTBOUND_PROXY')
76
                . ':' . Environment::getEnv('SS_OUTBOUND_PROXY_PORT');
77
        }
78
        return $proxy;
79
    }
80
81
    /**
82
     * Render the page as PDF using wkhtmltopdf.
83
     *
84
     * @return HTTPResponse|false
85
     */
86
    public function generatePDF()
87
    {
88
        if (!$this->owner->data()->config()->get('pdf_export')) {
89
            return false;
90
        }
91
92
        $binaryPath = $this->owner->data()->config()->get('wkhtmltopdf_binary');
93
        if (!$binaryPath || !is_executable($binaryPath)) {
94
            if (Environment::getEnv('WKHTMLTOPDF_BINARY')
95
                && is_executable(Environment::getEnv('WKHTMLTOPDF_BINARY'))
96
            ) {
97
                $binaryPath = Environment::getEnv('WKHTMLTOPDF_BINARY');
98
            }
99
        }
100
101
        if (!$binaryPath) {
102
            user_error(
103
                'Neither WKHTMLTOPDF_BINARY nor ' . get_class($this->owner->data()) . '.wkhtmltopdf_binary are defined',
104
                E_USER_ERROR
105
            );
106
        }
107
108
        if (Versioned::get_reading_mode() == 'Stage.Stage') {
109
            user_error('Generating PDFs on draft is not supported', E_USER_ERROR);
110
        }
111
112
        set_time_limit(60);
113
114
        // prepare the paths
115
        $pdfFile = $this->owner->data()->getPdfFilename();
116
        $bodyFile = str_replace('.pdf', '_pdf.html', $pdfFile);
117
        $footerFile = str_replace('.pdf', '_pdffooter.html', $pdfFile);
118
119
        // make sure the work directory exists
120
        if (!file_exists(dirname($pdfFile))) {
121
            Filesystem::makeFolder(dirname($pdfFile));
122
        }
123
124
        //decide the domain to use in generation
125
        $pdfBaseUrl = $this->owner->getPDFBaseURL();
126
127
        // Force http protocol on CWP - fetching from localhost without using the proxy, SSL terminates on gateway.
128
        if (Environment::getEnv('CWP_ENVIRONMENT')) {
129
            Config::modify()->set(Director::class, 'alternate_protocol', 'http');
130
            //only set alternate protocol if CWP_SECURE_DOMAIN is defined OR pdf_base_url is
131
            if ($pdfBaseUrl) {
132
                Config::modify()->set(Director::class, 'alternate_base_url', 'http://' . $pdfBaseUrl);
133
            }
134
        }
135
136
        $bodyViewer = $this->owner->getViewer('pdf');
137
138
        // write the output of this page to HTML, ready for conversion to PDF
139
        file_put_contents($bodyFile, $bodyViewer->process($this->owner));
140
141
        // get the viewer for the current template with _pdffooter
142
        $footerViewer = $this->owner->getViewer('pdffooter');
143
144
        // write the output of the footer template to HTML, ready for conversion to PDF
145
        file_put_contents($footerFile, $footerViewer->process($this->owner));
146
147
        //decide what the proxy should look like
148
        $proxy = $this->owner->getPDFProxy($pdfBaseUrl);
149
150
        // finally, generate the PDF
151
        $command = $binaryPath . $proxy . ' --outline -B 40pt -L 20pt -R 20pt -T 20pt --encoding utf-8 '
152
            . '--orientation Portrait --disable-javascript --quiet --print-media-type ';
153
        $retVal = 0;
154
        $output = [];
155
        exec(
156
            $command . " --footer-html \"$footerFile\" \"$bodyFile\" \"$pdfFile\" &> /dev/stdout",
157
            $output,
158
            $retVal
159
        );
160
161
        // remove temporary file
162
        unlink($bodyFile);
163
        unlink($footerFile);
164
165
        // output any errors
166
        if ($retVal != 0) {
0 ignored issues
show
The condition $retVal != 0 can never be true.
Loading history...
167
            user_error('wkhtmltopdf failed: ' . implode("\n", $output), E_USER_ERROR);
168
        }
169
170
        // serve the generated file
171
        return HTTPRequest::send_file(file_get_contents($pdfFile), basename($pdfFile), 'application/pdf');
172
    }
173
}
174