[BUGFIX] concatenateCSS may produce invalid css 23/22623/7
authorStefan Neufeind <typo3.neufeind@speedpartner.de>
Sun, 24 Nov 2013 22:11:18 +0000 (23:11 +0100)
committerStefan Neufeind <typo3.neufeind@speedpartner.de>
Thu, 6 Mar 2014 13:51:04 +0000 (14:51 +0100)
css-files with statements like @import might become corrupted. This is due
a wrong regex in case no quotes (single or double) are provided.

Adjust regex and add testcases.

Resolves: #50491
Releases: 6.2, 6.1
Change-Id: I8c35be97147da51e3cfc4be6de114f3c19c1abca
Reviewed-on: https://review.typo3.org/22623
Reviewed-by: Markus Klein
Tested-by: Markus Klein
Reviewed-by: Alexander Opitz
Tested-by: Alexander Opitz
Reviewed-by: Christian Kuhn
Tested-by: Christian Kuhn
Reviewed-by: Stefan Neufeind
Tested-by: Stefan Neufeind
typo3/sysext/core/Classes/Resource/ResourceCompressor.php
typo3/sysext/core/Tests/Unit/Resource/ResourceCompressorTest.php [new file with mode: 0644]

index 15a2241..ce17ee4 100644 (file)
@@ -666,13 +666,13 @@ class ResourceCompressor {
                if (stripos($contents, '@charset') === FALSE && stripos($contents, '@import') === FALSE && stripos($contents, '@namespace') === FALSE) {
                        return $contents;
                }
-               $regex = '/@(charset|import|namespace)\\s*(url)?\\s*\\(?\\s*["\']?[^"\']+["\']?\\s*\\)?.*;/i';
+               $regex = '/@(charset|import|namespace)\\s*(url)?\\s*\\(?\\s*["\']?[^"\'\\)]+["\']?\\s*\\)?\\s*;/i';
                preg_match_all($regex, $contents, $matches);
                if (!empty($matches[0])) {
                        // remove existing statements
                        $contents = str_replace($matches[0], '', $contents);
                        // add statements to the top of contents in the order they occur in original file
-                       $contents = $comment . implode($comment, $matches[0]) . LF . $contents;
+                       $contents = $comment . implode($comment, $matches[0]) . LF . trim($contents);
                }
                return $contents;
        }
diff --git a/typo3/sysext/core/Tests/Unit/Resource/ResourceCompressorTest.php b/typo3/sysext/core/Tests/Unit/Resource/ResourceCompressorTest.php
new file mode 100644 (file)
index 0000000..a32305c
--- /dev/null
@@ -0,0 +1,92 @@
+<?php
+namespace TYPO3\CMS\Core\Tests\Unit\Resource;
+
+/***************************************************************
+ * Copyright notice
+ *
+ * (c) 2011-2013 Stefan Neufeind <info (at) speedpartner.de>
+ * (c) 2014 Markus Klein <klein.t3@mfc-linz.at>
+ * All rights reserved
+ *
+ * This script is part of the TYPO3 project. The TYPO3 project is
+ * free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The GNU General Public License can be found at
+ * http://www.gnu.org/copyleft/gpl.html.
+ *
+ * This script is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+use TYPO3\CMS\Core\Resource\ResourceCompressor;
+
+/**
+ * Testcase for the ResourceCompressor class
+ *
+ * @author Stefan Neufeind <info (at) speedpartner.de>
+ */
+class ResourceCompressorTest extends BaseTestCase {
+
+       /**
+        * @var \TYPO3\CMS\Core\Resource\ResourceCompressor
+        */
+       protected $subject;
+
+       /**
+        * Set up the test
+        */
+       public function setUp() {
+               parent::setUp();
+               $this->subject = $this->getAccessibleMock('TYPO3\\CMS\\Core\\Resource\\ResourceCompressor', array('dummy'));
+       }
+
+       /**
+        * @return array
+        */
+       public function cssFixStatementsDataProvider() {
+               return array(
+                       'nothing to do - no charset/import/namespace' => array(
+                               'body { background: #ffffff; }',
+                               'body { background: #ffffff; }'
+                       ),
+                       'import in front' => array(
+                               '@import url(http://www.example.com/css); body { background: #ffffff; }',
+                               'LF/* moved by compressor */LF@import url(http://www.example.com/css);LFbody { background: #ffffff; }'
+                       ),
+                       'import in back, without quotes' => array(
+                               'body { background: #ffffff; } @import url(http://www.example.com/css);',
+                               'LF/* moved by compressor */LF@import url(http://www.example.com/css);LFbody { background: #ffffff; }'
+                       ),
+                       'import in back, with double-quotes' => array(
+                               'body { background: #ffffff; } @import url("http://www.example.com/css");',
+                               'LF/* moved by compressor */LF@import url("http://www.example.com/css");LFbody { background: #ffffff; }'
+                       ),
+                       'import in back, with single-quotes' => array(
+                               'body { background: #ffffff; } @import url(\'http://www.example.com/css\');',
+                               'LF/* moved by compressor */LF@import url(\'http://www.example.com/css\');LFbody { background: #ffffff; }'
+                       ),
+                       'import in middle and back, without quotes' => array(
+                               'body { background: #ffffff; } @import url(http://www.example.com/A); div { background: #000; } @import url(http://www.example.com/B);',
+                               'LF/* moved by compressor */LF@import url(http://www.example.com/A);LF/* moved by compressor */LF@import url(http://www.example.com/B);LFbody { background: #ffffff; }  div { background: #000; }'
+                       ),
+               );
+       }
+
+       /**
+        * @test
+        * @dataProvider cssFixStatementsDataProvider
+        */
+       public function cssFixStatementsMovesStatementsToTopIfNeeded($input, $expected) {
+               $result = $this->subject->_call('cssFixStatements', $input);
+               $resultWithReadableLinefeed = str_replace(LF, 'LF', $result);
+               $this->assertEquals($expected, $resultWithReadableLinefeed);
+       }
+
+}
\ No newline at end of file