1<?php
2
3/*
4 * This file is part of the Assetic package, an OpenSky project.
5 *
6 * (c) 2010-2014 OpenSky Project Inc
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Assetic\Filter\GoogleClosure;
13
14use Assetic\Asset\AssetInterface;
15
16/**
17 * Filter for the Google Closure Compiler API.
18 *
19 * @link https://developers.google.com/closure/compiler/
20 * @author Kris Wallsmith <kris.wallsmith@gmail.com>
21 */
22class CompilerApiFilter extends BaseCompilerFilter
23{
24    private $proxy;
25    private $proxyFullUri;
26
27    public function setProxy($proxy)
28    {
29        $this->proxy = $proxy;
30    }
31
32    public function setProxyFullUri($proxyFullUri)
33    {
34        $this->proxyFullUri = $proxyFullUri;
35    }
36
37    public function filterDump(AssetInterface $asset)
38    {
39        $query = array(
40            'js_code'       => $asset->getContent(),
41            'output_format' => 'json',
42            'output_info'   => 'compiled_code',
43        );
44
45        if (null !== $this->compilationLevel) {
46            $query['compilation_level'] = $this->compilationLevel;
47        }
48
49        if (null !== $this->jsExterns) {
50            $query['js_externs'] = $this->jsExterns;
51        }
52
53        if (null !== $this->externsUrl) {
54            $query['externs_url'] = $this->externsUrl;
55        }
56
57        if (null !== $this->excludeDefaultExterns) {
58            $query['exclude_default_externs'] = $this->excludeDefaultExterns ? 'true' : 'false';
59        }
60
61        if (null !== $this->formatting) {
62            $query['formatting'] = $this->formatting;
63        }
64
65        if (null !== $this->useClosureLibrary) {
66            $query['use_closure_library'] = $this->useClosureLibrary ? 'true' : 'false';
67        }
68
69        if (null !== $this->warningLevel) {
70            $query['warning_level'] = $this->warningLevel;
71        }
72
73        if (null !== $this->language) {
74            $query['language'] = $this->language;
75        }
76
77        if (preg_match('/1|yes|on|true/i', ini_get('allow_url_fopen'))) {
78            $contextOptions = array('http' => array(
79                'method'  => 'POST',
80                'header'  => 'Content-Type: application/x-www-form-urlencoded',
81                'content' => http_build_query($query),
82            ));
83            if (null !== $this->timeout) {
84                $contextOptions['http']['timeout'] = $this->timeout;
85            }
86            if ($this->proxy) {
87                $contextOptions['http']['proxy'] = $this->proxy;
88                $contextOptions['http']['request_fulluri'] = (Boolean) $this->proxyFullUri;
89            }
90            $context = stream_context_create($contextOptions);
91
92            $response = file_get_contents('http://closure-compiler.appspot.com/compile', false, $context);
93            $data = json_decode($response);
94        } elseif (defined('CURLOPT_POST') && !in_array('curl_init', explode(',', ini_get('disable_functions')))) {
95            $ch = curl_init('http://closure-compiler.appspot.com/compile');
96            curl_setopt($ch, CURLOPT_POST, true);
97            curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/x-www-form-urlencoded'));
98            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
99            curl_setopt($ch, CURLOPT_POSTFIELDS, $query);
100            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
101            if (null !== $this->timeout) {
102                curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
103            }
104            if ($this->proxy) {
105                curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, true);
106                curl_setopt($ch, CURLOPT_PROXY, $this->proxy);
107            }
108            $response = curl_exec($ch);
109            curl_close($ch);
110
111            $data = json_decode($response);
112        } else {
113            throw new \RuntimeException("There is no known way to contact closure compiler available");
114        }
115
116        if (isset($data->serverErrors) && 0 < count($data->serverErrors)) {
117            // @codeCoverageIgnoreStart
118            throw new \RuntimeException(sprintf('The Google Closure Compiler API threw some server errors: '.print_r($data->serverErrors, true)));
119            // @codeCoverageIgnoreEnd
120        }
121
122        if (isset($data->errors) && 0 < count($data->errors)) {
123            // @codeCoverageIgnoreStart
124            throw new \RuntimeException(sprintf('The Google Closure Compiler API threw some errors: '.print_r($data->errors, true)));
125            // @codeCoverageIgnoreEnd
126        }
127
128        $asset->setContent($data->compiledCode);
129    }
130}
131