Staticify::getDomain()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 2
eloc 6
nc 2
nop 0
dl 0
loc 10
ccs 6
cts 6
cp 1
crap 2
rs 9.4285
c 1
b 0
f 1
1
<?php
2
/**
3
 * Staticify.php
4
 * @author: [email protected]
5
 */
6
7
namespace FMUP\Dispatcher\Plugin;
8
9
/**
10
 * Class Staticify
11
 * this component is a POST dispatcher
12
 * it will replace all asset url to attack statics ones
13
 * This will allow cookie free domain + improve parallels asset download
14
 *
15
 * @package FMUP\Dispatcher\Plugin
16
 */
17
class Staticify extends \FMUP\Dispatcher\Plugin
18
{
19
    const PROTOCOL = '://';
20
21
    protected $name = 'Staticify';
22
    /**
23
     * Number of static instances
24
     * @var int
25
     */
26
    protected $staticNumber = 3;
27
28
    /**
29
     * Prefix of static instances
30
     * @var string
31
     */
32
    protected $staticPrefix = 'static';
33
34
    /**
35
     * Suffix of static instances
36
     * @var string
37
     */
38
    protected $staticSuffix = '';
39
    /**
40
     * SubDomain to replace
41
     * @var string
42
     */
43
    protected $subDomain = 'www';
44
    /**
45
     * Domain to replace
46
     * @var string
47
     */
48
    protected $domain = null;
49
50
    /**
51
     * Current asset
52
     * @var int
53
     */
54
    private $currentAsset = 1;
55
56
    /**
57
     * Path between domain and requested asset for relative urls
58
     * @var string
59
     */
60
    private $trailingPath;
61
62
    /**
63
     * Will catch all resources URL
64
     *
65
     * @see self::computeAsset
66
     */
67 2
    public function handle()
68
    {
69 2
        $response = $this->getResponse()->getBody();
70 2
        $newResponse = $response;
71 2
        $isJson = $this->isRequestJson();
72 2
        if ($isJson) {
73 1
            $response = stripslashes($response);
74
        }
75
        $regexps = array(
76 2
            '~<[^>]+\ssrc=["\']([^"\']+)["\']~',
77
            '~<link\s[^>]*href=["\']([^"\']+)["\']~',
78
        );
79 2
        $values = array();
80 2
        foreach ($regexps as $exp) {
81 2
            preg_match_all($exp, $response, $glob);
82 2
            foreach ($glob[1] as $string) {
83 2
                $crc = crc32($string);
84 2
                if (!isset($values[$crc])) {
85 2
                    $newResponse = str_replace(
86 2
                        $this->jsonTransform($string, $isJson),
87 2
                        $this->computeAsset($string, $isJson),
88 2
                        $newResponse
89
                    );
90 2
                    $values[$crc] = 1;
91
                }
92
            }
93
        }
94 2
        $this->getResponse()->setBody($newResponse);
95 2
    }
96
97
    /**
98
     * Check whether response is json or not
99
     * @return bool
100
     * @throws \FMUP\Exception
101
     */
102 2
    private function isRequestJson()
103
    {
104 2
        $isJson = false;
105 2
        foreach ($this->getResponse()->getHeaders() as $type => $items) {
106 1
            if ($type == \FMUP\Response\Header\ContentType::TYPE) {
107 1
                foreach ($items as $item) {
108 1
                    if ($item instanceof \FMUP\Response\Header\ContentType &&
109 1
                        $item->getMime() == \FMUP\Response\Header\ContentType::MIME_APPLICATION_JSON
110
                    ) {
111 1
                        $isJson = true;
112 1
                        break;
113
                    }
114
                }
115
            }
116
        }
117 2
        return $isJson;
118
    }
119
120
    /**
121
     * add slashes to / character in json mode
122
     * @param string $string
123
     * @param bool $isJson
124
     * @return mixed
125
     */
126 2
    private function jsonTransform($string, $isJson)
127
    {
128 2
        return $isJson ? str_replace('/', '\/', $string) : $string;
129
    }
130
131
    /**
132
     * Compute which asset for a path and return the full path
133
     *
134
     * @param string $path
135
     * @param bool $isJson Check if url should be encoded
136
     *
137
     * @return string
138
     */
139 2
    protected function computeAsset($path, $isJson = false)
140
    {
141 2
        if (strpos($path, self::PROTOCOL) !== false) {
142 2
            return $this->jsonTransform($path, $isJson);
143
        }
144 2
        $trailingPath = ($path{0} !== '/') ? $this->getAssetPath() : '';
145 2
        $path = $this->getDomain() . $trailingPath . $path;
146 2
        $path = str_replace(
147 2
            self::PROTOCOL . $this->getSubDomain(),
148 2
            self::PROTOCOL . $this->getStaticPrefix() . $this->currentAsset++ . $this->getStaticSuffix(),
149 2
            $path
150
        );
151 2
        if ($this->currentAsset > $this->getStaticNumber()) {
152 2
            $this->currentAsset = 1;
153
        }
154 2
        return $this->jsonTransform($path, $isJson);
155
    }
156
157
    /**
158
     * Compute relative path between requested asset and current path on request URI
159
     * @return string
160
     * @throws \FMUP\Exception
161
     */
162 2
    private function getAssetPath()
163
    {
164 2
        if (!$this->trailingPath) {
165 2
            $request = $this->getRequest();
166
            /** @var $request \FMUP\Request\Http */
167 2
            $uri = $request->getServer(\FMUP\Request\Http::REQUEST_URI);
168 2
            $this->trailingPath = ($uri{strlen($uri) - 1} == '/' ? dirname($uri . 'random') : dirname($uri)) . '/';
169
        }
170 2
        return $this->trailingPath;
171
    }
172
173
    /**
174
     * @param int $number
175
     * @return $this
176
     */
177 1
    public function setStaticNumber($number = 3)
178
    {
179 1
        $this->staticNumber = (int)$number;
180 1
        return $this;
181
    }
182
183
    /**
184
     * @return int
185
     */
186 3
    public function getStaticNumber()
187
    {
188 3
        return $this->staticNumber;
189
    }
190
191
    /**
192
     * @param string $prefix
193
     * @return $this
194
     */
195 1
    public function setStaticPrefix($prefix = 'static')
196
    {
197 1
        $this->staticPrefix = (string)$prefix;
198 1
        return $this;
199
    }
200
201
    /**
202
     * @return string
203
     */
204 2
    public function getStaticPrefix()
205
    {
206 2
        return $this->staticPrefix;
207
    }
208
209
    /**
210
     * @param string $suffix
211
     * @return $this
212
     */
213 1
    public function setStaticSuffix($suffix = '')
214
    {
215 1
        $this->staticSuffix = (string)$suffix;
216 1
        return $this;
217
    }
218
219
    /**
220
     * @return string
221
     */
222 2
    public function getStaticSuffix()
223
    {
224 2
        return $this->staticSuffix;
225
    }
226
227
    /**
228
     * @param string $subDomain
229
     * @return $this
230
     */
231 1
    public function setSubDomain($subDomain = 'www')
232
    {
233 1
        $this->subDomain = (string)$subDomain;
234 1
        return $this;
235
    }
236
237
    /**
238
     * @return string
239
     */
240 2
    public function getSubDomain()
241
    {
242 2
        return $this->subDomain;
243
    }
244
245
    /**
246
     * @return string
247
     * @throws \FMUP\Exception
248
     */
249 1
    public function getDomain()
250
    {
251 1
        if ($this->domain === null) {
252
            /** @var \FMUP\Request\Http $request */
253 1
            $request = $this->getRequest();
254 1
            $this->domain = $request->getServer(\FMUP\Request\Http::REQUEST_SCHEME)
255 1
                . self::PROTOCOL . $request->getServer(\FMUP\Request\Http::HTTP_HOST);
256
        }
257 1
        return $this->domain;
258
    }
259
260
    /**
261
     * Define domain to use for static assets
262
     * @param string|null $domain
263
     * @return $this
264
     */
265 1
    public function setDomain($domain = null)
266
    {
267 1
        $this->domain = $domain === null ? null : (string)$domain;
268 1
        return $this;
269
    }
270
}
271