CSS::expandImports()   B
last analyzed

Complexity

Conditions 6
Paths 6

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 20
ccs 16
cts 16
cp 1
rs 8.8571
c 0
b 0
f 0
cc 6
eloc 10
nc 6
nop 1
crap 6
1
<?php
2
/**
3
 * CSS.php
4
 * @author Revin Roman
5
 * @link https://processfast.com
6
 */
7
8
namespace processfast\yii\minify\components;
9
10
use yii\helpers\Html;
11
12
/**
13
 * Class CSS
14
 * @package processfast\yii\minify\components
15
 */
16
class CSS extends MinifyComponent
17
{
18
19 8
    public function export()
20
    {
21 8
        $cssFiles = $this->view->cssFiles;
22
23 8
        $this->view->cssFiles = [];
24
25 8
        $toMinify = [];
26
27 8 View Code Duplication
        if (!empty($cssFiles)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
28 7
            foreach ($cssFiles as $file => $html) {
29 7
                if ($this->thisFileNeedMinify($file, $html)) {
30 7
                    if ($this->view->concatCss) {
31 7
                        $toMinify[$file] = $html;
32 7
                    } else {
33
                        $this->process([$file => $html]);
34
                    }
35 7
                } else {
36 2
                    if (!empty($toMinify)) {
37 2
                        $this->process($toMinify);
38
39 2
                        $toMinify = [];
40 2
                    }
41
42 2
                    $this->view->cssFiles[$file] = $html;
43
                }
44 7
            }
45 7
        }
46
47 8
        if (!empty($toMinify)) {
48 5
            $this->process($toMinify);
49 5
        }
50
51 8
        unset($toMinify);
52 8
    }
53
54
    /**
55
     * @param array $files
56
     */
57 7
    protected function process(array $files)
58
    {
59 7
        $hash = $this->_getSummaryFilesHash($files) ;
60 7
        $resultFile = $this->view->minifyPath . DIRECTORY_SEPARATOR . $hash . '.css';
61
62 7
        if(  $this->view->S3Upload && $this->doesObjectExist( $resultFile , "CSS" , $hash ) )
63 7
        {
64
            // It exist on s3 just do not do any processing
65
            $resultFile = $this->getS3Path( $resultFile , "CSS" , $hash );
66
        }
67 7
        else if (!file_exists($resultFile))
68 7
        {
69 7
            $css = '';
70
71 7
            foreach ($files as $file => $html) {
72 7
                $path = dirname($file);
73
74 7
                if( $this->view->S3Upload )
75 7
                {
76
                    $assetsFolderPathPatch = $this->view->assetsFolderPathPatch ;
77
                    $pathArray = explode('assets', $path, 2);
78
                    $newPath = $pathArray[1] ;
79
                    $path = $assetsFolderPathPatch."assets".$newPath ;
80
                }
81
82 7
                $file = $this->getAbsoluteFilePath($file);
83
84 7
                $content = '';
85
86 7
                if (!file_exists($file)) {
87
                    \Yii::warning(sprintf('Asset file not found `%s`', $file), __METHOD__);
88 7
                } elseif (!is_readable($file)) {
89
                    \Yii::warning(sprintf('Asset file not readable `%s`', $file), __METHOD__);
90
                } else {
91 7
                    $content = file_get_contents($file);
92
                }
93
94 7
                $result = [];
95
96 7
                preg_match_all('|url\(([^)]+)\)|is', $content, $m);
97 7
                if (!empty($m[0])) {
98 7
                    foreach ($m[0] as $k => $v) {
99 7
                        if (in_array(strpos($m[1][$k], 'data:'), [0, 1], true)) {
100 7
                            continue;
101
                        }
102
103 7
                        $url = str_replace(['\'', '"'], '', $m[1][$k]);
104
105 7
                        if ($this->isUrl($url)) {
106 7
                            $result[$m[1][$k]] = $url;
107 7
                        } else {
108 7
                            $result[$m[1][$k]] = $path . '/' . $url;
109
                        }
110 7
                    }
111
112 7
                    $content = strtr($content, $result);
113 7
                }
114
115 7
                $css .= $content;
116 7
            }
117
118 7
            $this->expandImports($css);
119
120 7
            $this->removeCssComments($css);
121
122 7
            if ($this->view->minifyCss) {
123 7
                $css = (new \CSSmin())
124 7
                    ->run($css, $this->view->cssLinebreakPos);
125 7
            }
126
127 7
            $charsets = false !== $this->view->forceCharset
128 7
                ? ('@charset "' . (string)$this->view->forceCharset . '";' . "\n")
129 7
                : $this->collectCharsets($css);
130
131 7
            $imports = $this->collectImports($css);
132 7
            $fonts = $this->collectFonts($css);
133
134 7
            $content = $charsets . $imports . $fonts . $css ;
135 7
            if( $this->view->gzipEncodeCss ){
136
                $content = gzencode( $content ,  9);
137
            }
138 7
            file_put_contents($resultFile, $content );
139
140 7
            if (false !== $this->view->fileMode) {
141 7
                @chmod($resultFile, $this->view->fileMode);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
142 7
            }
143
144 7
            if( $this->view->S3Upload )
145 7
            {
146
                $resultFile = $this->uploadToS3( $resultFile , "CSS" , $hash );
147
            }
148 7
        }
149
        else
150
        {
151
            if( $this->view->S3Upload )
152
            {
153
                $resultFile = $this->uploadToS3( $resultFile , "CSS" , $hash );
154
            }
155
        }
156
157 7
        $file = $this->prepareResultFile($resultFile);
158
159 7
        $this->view->cssFiles[$file] = Html::cssFile($file);
160 7
    }
161
162
    /**
163
     * @param string $code
164
     */
165 7
    protected function removeCssComments(&$code)
166
    {
167 7
        if (true === $this->view->removeComments) {
168
169
            //https://stackoverflow.com/questions/1581049/preg-replace-out-css-comments
170
            $regex = array(
171 7
                "`^([\t\s]+)`ism"=>'',
172 7
                "`^\/\*(.+?)\*\/`ism"=>"",
173 7
                "`([\n\A;]+)\/\*(.+?)\*\/`ism"=>"$1",
174 7
                "`([\n\A;\s]+)//(.+?)[\n\r]`ism"=>"$1\n",
175
                "`(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+`ism"=>"\n"
176 7
            );
177 7
            $code = preg_replace(array_keys($regex),$regex,$code);
178 7
        }
179 7
    }
180
181
    /**
182
     * @param string $code
183
     */
184 7
    protected function expandImports(&$code)
185
    {
186 7
        if (true === $this->view->expandImports) {
187 7
            preg_match_all('|\@import\s([^;]+);|is', str_replace('&amp;', '&', $code), $m);
188
189 7
            if (!empty($m[0])) {
190 7
                foreach ($m[0] as $k => $v) {
191 7
                    $import_url = $m[1][$k];
192
193 7
                    if (!empty($import_url)) {
194 7
                        $import_content = $this->_getImportContent($import_url);
195
196 7
                        if (!empty($import_content)) {
197 7
                            $code = str_replace($m[0][$k], $import_content, $code);
198 7
                        }
199 7
                    }
200 7
                }
201 7
            }
202 7
        }
203 7
    }
204
205
    /**
206
     * @param string $code
207
     * @return string
208
     */
209
    protected function collectCharsets(&$code)
210
    {
211
        return $this->_collect($code, '|\@charset[^;]+|is', function ($string) {
212
            return $string . ';';
213
        });
214
    }
215
216
    /**
217
     * @param string $code
218
     * @return string
219
     */
220 7
    protected function collectImports(&$code)
221
    {
222
        return $this->_collect($code, '|\@import[^;]+|is', function ($string) {
223
            return $string . ';';
224 7
        });
225
    }
226
227
    /**
228
     * @param string $code
229
     * @return string
230
     */
231
    protected function collectFonts(&$code)
232
    {
233 7
        return $this->_collect($code, '|\@font-face\{[^}]+\}|is', function ($string) {
234 7
            return $string;
235 7
        });
236
    }
237
238
    /**
239
     * @param string $code
240
     * @param string $pattern
241
     * @param callable $handler
242
     * @return string
243
     */
244 7
    protected function _collect(&$code, $pattern, $handler)
245
    {
246 7
        $result = '';
247
248 7
        preg_match_all($pattern, $code, $m);
249
250 7
        foreach ($m[0] as $string) {
251 7
            $string = $handler($string);
252 7
            $code = str_replace($string, '', $code);
253
254 7
            $result .= $string . PHP_EOL;
255 7
        }
256
257 7
        return $result;
258
    }
259
260
    /**
261
     * @param string $url
262
     * @return null|string
263
     */
264 7
    protected function _getImportContent($url)
265
    {
266 7
        $result = null;
267
268 7
        if ('url(' === mb_substr($url, 0, 4)) {
269 7
            $url = str_replace(['url(\'', 'url("', 'url(', '\')', '")', ')'], '', $url);
270
271 7
            if (mb_substr($url, 0, 2) === '//') {
272 7
                $url = preg_replace('|^//|', 'http://', $url, 1);
273 7
            }
274
275 7
            if (!empty($url)) {
276 7
                if (!in_array(mb_substr($url, 0, 4), ['http', 'ftp:'], true)) {
277 7
                    $url = \Yii::getAlias($this->view->basePath . $url);
278 7
                }
279
280
                $context = [
281
                    'ssl' => [
282 7
                        'verify_peer' => false,
283 7
                        'verify_peer_name' => false,
284 7
                    ],
285 7
                ];
286
287 7
                $result = file_get_contents($url, null, stream_context_create($context));
288 7
            }
289 7
        }
290
291 7
        return $result;
292
    }
293
}
294