vendor/contao/core-bundle/src/Resources/contao/classes/StyleSheets.php line 13

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of Contao.
  4.  *
  5.  * (c) Leo Feyer
  6.  *
  7.  * @license LGPL-3.0-or-later
  8.  */
  9. namespace Contao;
  10. trigger_deprecation('contao/core-bundle''4.13''Using the "Contao\StyleSheets" class has been deprecated and will no longer work in Contao 5.0. Use external stylesheets instead.');
  11. /**
  12.  * Provide methods to handle style sheets.
  13.  *
  14.  * @deprecated Deprecated since Contao 4.13, to be removed in Contao 5.0.
  15.  *             Use external stylesheets instead.
  16.  */
  17. class StyleSheets extends Backend
  18. {
  19.     /**
  20.      * @var string
  21.      */
  22.     protected $strRootDir;
  23.     /**
  24.      * Import the Files library
  25.      */
  26.     public function __construct()
  27.     {
  28.         parent::__construct();
  29.         $this->import(Files::class, 'Files');
  30.         $this->strRootDir System::getContainer()->getParameter('kernel.project_dir');
  31.     }
  32.     /**
  33.      * Update a particular style sheet
  34.      *
  35.      * @param integer $intId
  36.      */
  37.     public function updateStyleSheet($intId)
  38.     {
  39.         $objStyleSheet $this->Database->prepare("SELECT * FROM tl_style_sheet WHERE id=?")
  40.                                         ->limit(1)
  41.                                         ->execute($intId);
  42.         if ($objStyleSheet->numRows 1)
  43.         {
  44.             return;
  45.         }
  46.         // Delete the CSS file
  47.         if (Input::get('act') == 'delete')
  48.         {
  49.             $this->import(Files::class, 'Files');
  50.             $this->Files->delete('assets/css/' $objStyleSheet->name '.css');
  51.         }
  52.         // Update the CSS file
  53.         else
  54.         {
  55.             $this->writeStyleSheet($objStyleSheet->row());
  56.             System::getContainer()->get('monolog.logger.contao.cron')->info('Generated style sheet "' $objStyleSheet->name '.css"');
  57.         }
  58.     }
  59.     /**
  60.      * Update all style sheets in the scripts folder
  61.      */
  62.     public function updateStyleSheets()
  63.     {
  64.         $objStyleSheets $this->Database->execute("SELECT * FROM tl_style_sheet");
  65.         $arrStyleSheets $objStyleSheets->fetchEach('name');
  66.         // Make sure the dcaconfig.php file is loaded
  67.         if (file_exists($this->strRootDir '/system/config/dcaconfig.php'))
  68.         {
  69.             trigger_deprecation('contao/core-bundle''4.3''Using the "dcaconfig.php" file has been deprecated and will no longer work in Contao 5.0. Create custom DCA files in the "contao/dca" folder instead.');
  70.             include $this->strRootDir '/system/config/dcaconfig.php';
  71.         }
  72.         // Delete old style sheets
  73.         foreach (Folder::scan($this->strRootDir '/assets/css'true) as $file)
  74.         {
  75.             // Skip directories
  76.             if (is_dir($this->strRootDir '/assets/css/' $file))
  77.             {
  78.                 continue;
  79.             }
  80.             // Preserve root files (is this still required now that scripts are in assets/css/scripts?)
  81.             if (\is_array(Config::get('rootFiles')) && \in_array($fileConfig::get('rootFiles')))
  82.             {
  83.                 continue;
  84.             }
  85.             // Do not delete the combined files (see #3605)
  86.             if (preg_match('/^[a-f0-9]{12}\.css$/'$file))
  87.             {
  88.                 continue;
  89.             }
  90.             $objFile = new File('assets/css/' $file);
  91.             // Delete the old style sheet
  92.             if ($objFile->extension == 'css' && !\in_array($objFile->filename$arrStyleSheets))
  93.             {
  94.                 $objFile->delete();
  95.             }
  96.         }
  97.         $objStyleSheets->reset();
  98.         // Create the new style sheets
  99.         while ($objStyleSheets->next())
  100.         {
  101.             $this->writeStyleSheet($objStyleSheets->row());
  102.             System::getContainer()->get('monolog.logger.contao.cron')->info('Generated style sheet "' $objStyleSheets->name '.css"');
  103.         }
  104.     }
  105.     /**
  106.      * Write a style sheet to a file
  107.      *
  108.      * @param array $row
  109.      */
  110.     protected function writeStyleSheet($row)
  111.     {
  112.         if ($row['id'] == '' || $row['name'] == '')
  113.         {
  114.             return;
  115.         }
  116.         $row['name'] = basename($row['name']);
  117.         // Check whether the target file is writeable
  118.         if (file_exists($this->strRootDir '/assets/css/' $row['name'] . '.css') && !$this->Files->is_writeable('assets/css/' $row['name'] . '.css'))
  119.         {
  120.             Message::addError(sprintf($GLOBALS['TL_LANG']['ERR']['notWriteable'], 'assets/css/' $row['name'] . '.css'));
  121.             return;
  122.         }
  123.         $vars = array();
  124.         // Get the global theme variables
  125.         $objTheme $this->Database->prepare("SELECT vars FROM tl_theme WHERE id=?")
  126.                                    ->limit(1)
  127.                                    ->execute($row['pid']);
  128.         if ($objTheme->vars != '' && \is_array(($tmp StringUtil::deserialize($objTheme->vars))))
  129.         {
  130.             foreach ($tmp as $v)
  131.             {
  132.                 $vars[$v['key']] = $v['value'];
  133.             }
  134.         }
  135.         // Merge the global style sheet variables
  136.         if (!empty($row['vars']) && \is_array($tmp StringUtil::deserialize($row['vars'])))
  137.         {
  138.             foreach ($tmp as $v)
  139.             {
  140.                 $vars[$v['key']] = $v['value'];
  141.             }
  142.         }
  143.         // Sort by key length (see #3316)
  144.         uksort($vars, static function ($a$b): int
  145.         {
  146.             return \strlen($b) - \strlen($a);
  147.         });
  148.         // Create the file
  149.         $objFile = new File('assets/css/' $row['name'] . '.css');
  150.         $objFile->write('/* ' $row['name'] . ".css */\n");
  151.         $objDefinitions $this->Database->prepare("SELECT * FROM tl_style WHERE pid=? AND invisible!='1' ORDER BY sorting")
  152.                                          ->execute($row['id']);
  153.         // Append the definition
  154.         while ($objDefinitions->next())
  155.         {
  156.             $objFile->append($this->compileDefinition($objDefinitions->row(), true$vars$row), '');
  157.         }
  158.         $objFile->close();
  159.     }
  160.     /**
  161.      * Compile format definitions and return them as string
  162.      *
  163.      * @param array   $row
  164.      * @param boolean $blnWriteToFile
  165.      * @param array   $vars
  166.      * @param array   $parent
  167.      * @param boolean $export
  168.      *
  169.      * @return string
  170.      */
  171.     public function compileDefinition($row$blnWriteToFile=false$vars=array(), $parent=array(), $export=false)
  172.     {
  173.         if ($blnWriteToFile)
  174.         {
  175.             $strGlue '../../';
  176.             $lb '';
  177.             $return '';
  178.         }
  179.         elseif ($export)
  180.         {
  181.             $strGlue '';
  182.             $lb "\n    ";
  183.             $return '';
  184.         }
  185.         else
  186.         {
  187.             $strGlue '';
  188.             $lb "\n    ";
  189.             $return "\n" '<pre' . ($row['invisible'] ? ' class="disabled"' '') . '>';
  190.         }
  191.         // Comment
  192.         if ((!$blnWriteToFile || $export) && $row['comment'] != '')
  193.         {
  194.             $search = array('@^\s*/\*+@''@\*+/\s*$@');
  195.             $comment preg_replace($search''$row['comment']);
  196.             if ($export)
  197.             {
  198.                 $return .= "\n/* " $comment " */\n";
  199.             }
  200.             else
  201.             {
  202.                 $comment wordwrap(trim($comment), 72);
  203.                 $return .= "\n" '<span class="comment">' $comment '</span>' "\n";
  204.             }
  205.         }
  206.         // Selector
  207.         $arrSelector StringUtil::trimsplit(','StringUtil::decodeEntities($row['selector']));
  208.         $return .= implode(($blnWriteToFile ',' ",\n"), $arrSelector) . ($blnWriteToFile '' ' ') . '{';
  209.         // Size
  210.         if ($row['size'])
  211.         {
  212.             // Width
  213.             $row['width'] = StringUtil::deserialize($row['width']);
  214.             if (isset($row['width']['value']) && $row['width']['value'] != '')
  215.             {
  216.                 $return .= $lb 'width:' $row['width']['value'] . (($row['width']['value'] == 'auto') ? '' $row['width']['unit']) . ';';
  217.             }
  218.             // Height
  219.             $row['height'] = StringUtil::deserialize($row['height']);
  220.             if (isset($row['height']['value']) && $row['height']['value'] != '')
  221.             {
  222.                 $return .= $lb 'height:' $row['height']['value'] . (($row['height']['value'] == 'auto') ? '' $row['height']['unit']) . ';';
  223.             }
  224.             // Min-width
  225.             $row['minwidth'] = StringUtil::deserialize($row['minwidth']);
  226.             if (isset($row['minwidth']['value']) && $row['minwidth']['value'] != '')
  227.             {
  228.                 $return .= $lb 'min-width:' $row['minwidth']['value'] . (($row['minwidth']['value'] == 'inherit') ? '' $row['minwidth']['unit']) . ';';
  229.             }
  230.             // Min-height
  231.             $row['minheight'] = StringUtil::deserialize($row['minheight']);
  232.             if (isset($row['minheight']['value']) && $row['minheight']['value'] != '')
  233.             {
  234.                 $return .= $lb 'min-height:' $row['minheight']['value'] . (($row['minheight']['value'] == 'inherit') ? '' $row['minheight']['unit']) . ';';
  235.             }
  236.             // Max-width
  237.             $row['maxwidth'] = StringUtil::deserialize($row['maxwidth']);
  238.             if (isset($row['maxwidth']['value']) && $row['maxwidth']['value'] != '')
  239.             {
  240.                 $return .= $lb 'max-width:' $row['maxwidth']['value'] . (($row['maxwidth']['value'] == 'inherit' || $row['maxwidth']['value'] == 'none') ? '' $row['maxwidth']['unit']) . ';';
  241.             }
  242.             // Max-height
  243.             $row['maxheight'] = StringUtil::deserialize($row['maxheight']);
  244.             if (isset($row['maxheight']['value']) && $row['maxheight']['value'] != '')
  245.             {
  246.                 $return .= $lb 'max-height:' $row['maxheight']['value'] . (($row['maxheight']['value'] == 'inherit' || $row['maxheight']['value'] == 'none') ? '' $row['maxheight']['unit']) . ';';
  247.             }
  248.         }
  249.         // Position
  250.         if ($row['positioning'])
  251.         {
  252.             // Top/right/bottom/left
  253.             $row['trbl'] = StringUtil::deserialize($row['trbl']);
  254.             if (\is_array($row['trbl']))
  255.             {
  256.                 foreach ($row['trbl'] as $k=>$v)
  257.                 {
  258.                     if ($v != '' && $k != 'unit')
  259.                     {
  260.                         $return .= $lb $k ':' $v . (($v == 'auto' || $v === '0') ? '' $row['trbl']['unit']) . ';';
  261.                     }
  262.                 }
  263.             }
  264.             // Position
  265.             if ($row['position'] != '')
  266.             {
  267.                 $return .= $lb 'position:' $row['position'] . ';';
  268.             }
  269.             // Overflow
  270.             if ($row['overflow'] != '')
  271.             {
  272.                 $return .= $lb 'overflow:' $row['overflow'] . ';';
  273.             }
  274.             // Float
  275.             if ($row['floating'] != '')
  276.             {
  277.                 $return .= $lb 'float:' $row['floating'] . ';';
  278.             }
  279.             // Clear
  280.             if ($row['clear'] != '')
  281.             {
  282.                 $return .= $lb 'clear:' $row['clear'] . ';';
  283.             }
  284.             // Display
  285.             if ($row['display'] != '')
  286.             {
  287.                 $return .= $lb 'display:' $row['display'] . ';';
  288.             }
  289.         }
  290.         // Margin, padding and alignment
  291.         if ($row['alignment'])
  292.         {
  293.             // Margin
  294.             if ($row['margin'] != '' || $row['align'] != '')
  295.             {
  296.                 $row['margin'] = StringUtil::deserialize($row['margin']);
  297.                 if (\is_array($row['margin']))
  298.                 {
  299.                     $top $row['margin']['top'];
  300.                     $right $row['margin']['right'];
  301.                     $bottom $row['margin']['bottom'];
  302.                     $left $row['margin']['left'];
  303.                     // Overwrite the left and right margin if an alignment is set
  304.                     if ($row['align'] != '')
  305.                     {
  306.                         if ($row['align'] == 'left' || $row['align'] == 'center')
  307.                         {
  308.                             $right 'auto';
  309.                         }
  310.                         if ($row['align'] == 'right' || $row['align'] == 'center')
  311.                         {
  312.                             $left 'auto';
  313.                         }
  314.                     }
  315.                     // Try to shorten the definition
  316.                     if ($top != '' && $right != '' && $bottom != '' && $left != '')
  317.                     {
  318.                         if ($top == $right && $top == $bottom && $top == $left)
  319.                         {
  320.                             $return .= $lb 'margin:' $top . (($top == 'auto' || $top === '0') ? '' $row['margin']['unit']) . ';';
  321.                         }
  322.                         elseif ($top == $bottom && $right == $left)
  323.                         {
  324.                             $return .= $lb 'margin:' $top . (($top == 'auto' || $top === '0') ? '' $row['margin']['unit']) . ' ' $right . (($right == 'auto' || $right === '0') ? '' $row['margin']['unit']) . ';';
  325.                         }
  326.                         elseif ($top != $bottom && $right == $left)
  327.                         {
  328.                             $return .= $lb 'margin:' $top . (($top == 'auto' || $top === '0') ? '' $row['margin']['unit']) . ' ' $right . (($right == 'auto' || $right === '0') ? '' $row['margin']['unit']) . ' ' $bottom . (($bottom == 'auto' || $bottom === '0') ? '' $row['margin']['unit']) . ';';
  329.                         }
  330.                         else
  331.                         {
  332.                             $return .= $lb 'margin:' $top . (($top == 'auto' || $top === '0') ? '' $row['margin']['unit']) . ' ' $right . (($right == 'auto' || $right === '0') ? '' $row['margin']['unit']) . ' ' $bottom . (($bottom == 'auto' || $bottom === '0') ? '' $row['margin']['unit']) . ' ' $left . (($left == 'auto' || $left === '0') ? '' $row['margin']['unit']) . ';';
  333.                         }
  334.                     }
  335.                     else
  336.                     {
  337.                         $arrDir compact('top''right''bottom''left');
  338.                         foreach ($arrDir as $k=>$v)
  339.                         {
  340.                             if ($v != '')
  341.                             {
  342.                                 $return .= $lb 'margin-' $k ':' $v . (($v == 'auto' || $v === '0') ? '' $row['margin']['unit']) . ';';
  343.                             }
  344.                         }
  345.                     }
  346.                 }
  347.             }
  348.             // Padding
  349.             if ($row['padding'] != '')
  350.             {
  351.                 $row['padding'] = StringUtil::deserialize($row['padding']);
  352.                 if (\is_array($row['padding']))
  353.                 {
  354.                     $top $row['padding']['top'];
  355.                     $right $row['padding']['right'];
  356.                     $bottom $row['padding']['bottom'];
  357.                     $left $row['padding']['left'];
  358.                     // Try to shorten the definition
  359.                     if ($top != '' && $right != '' && $bottom != '' && $left != '')
  360.                     {
  361.                         if ($top == $right && $top == $bottom && $top == $left)
  362.                         {
  363.                             $return .= $lb 'padding:' $top . (($top === '0') ? '' $row['padding']['unit']) . ';';
  364.                         }
  365.                         elseif ($top == $bottom && $right == $left)
  366.                         {
  367.                             $return .= $lb 'padding:' $top . (($top === '0') ? '' $row['padding']['unit']) . ' ' $right . (($right === '0') ? '' $row['padding']['unit']) . ';';
  368.                         }
  369.                         elseif ($top != $bottom && $right == $left)
  370.                         {
  371.                             $return .= $lb 'padding:' $top . (($top === '0') ? '' $row['padding']['unit']) . ' ' $right . (($right === '0') ? '' $row['padding']['unit']) . ' ' $bottom . (($bottom === '0') ? '' $row['padding']['unit']) . ';';
  372.                         }
  373.                         else
  374.                         {
  375.                             $return .= $lb 'padding:' $top . (($top === '0') ? '' $row['padding']['unit']) . ' ' $right . (($right === '0') ? '' $row['padding']['unit']) . ' ' $bottom . (($bottom === '0') ? '' $row['padding']['unit']) . ' ' $left . (($left === '0') ? '' $row['padding']['unit']) . ';';
  376.                         }
  377.                     }
  378.                     else
  379.                     {
  380.                         $arrDir compact('top''right''bottom''left');
  381.                         foreach ($arrDir as $k=>$v)
  382.                         {
  383.                             if ($v != '')
  384.                             {
  385.                                 $return .= $lb 'padding-' $k ':' $v . (($v === '0') ? '' $row['padding']['unit']) . ';';
  386.                             }
  387.                         }
  388.                     }
  389.                 }
  390.             }
  391.             // Vertical alignment
  392.             if ($row['verticalalign'] != '')
  393.             {
  394.                 $return .= $lb 'vertical-align:' $row['verticalalign'] . ';';
  395.             }
  396.             // Text alignment
  397.             if ($row['textalign'] != '')
  398.             {
  399.                 $return .= $lb 'text-align:' $row['textalign'] . ';';
  400.             }
  401.             // White space
  402.             if ($row['whitespace'] != '')
  403.             {
  404.                 $return .= $lb 'white-space:' $row['whitespace'] . ';';
  405.             }
  406.         }
  407.         // Background
  408.         if ($row['background'])
  409.         {
  410.             $bgColor StringUtil::deserialize($row['bgcolor'], true) + array('''');
  411.             // Try to shorten the definition
  412.             if ($bgColor[0] != '' && $row['bgimage'] != '' && $row['bgposition'] != '' && $row['bgrepeat'] != '')
  413.             {
  414.                 if (($strImage $this->generateBase64Image($row['bgimage'], $parent)) !== false)
  415.                 {
  416.                     $return .= $lb 'background:' $this->compileColor($bgColor$blnWriteToFile$vars) . ' url("' $strImage '") ' $row['bgposition'] . ' ' $row['bgrepeat'] . ';';
  417.                 }
  418.                 else
  419.                 {
  420.                     $glue = (strncmp($row['bgimage'], 'data:'5) !== && strncmp($row['bgimage'], 'http://'7) !== && strncmp($row['bgimage'], 'https://'8) !== && strncmp($row['bgimage'], '/'1) !== 0) ? $strGlue '';
  421.                     $return .= $lb 'background:' $this->compileColor($bgColor$blnWriteToFile$vars) . ' url("' $glue $row['bgimage'] . '") ' $row['bgposition'] . ' ' $row['bgrepeat'] . ';';
  422.                 }
  423.             }
  424.             else
  425.             {
  426.                 // Background color
  427.                 if ($bgColor[0] != '')
  428.                 {
  429.                     $return .= $lb 'background-color:' $this->compileColor($bgColor$blnWriteToFile$vars) . ';';
  430.                 }
  431.                 // Background image
  432.                 if ($row['bgimage'] == 'none')
  433.                 {
  434.                     $return .= $lb 'background-image:none;';
  435.                 }
  436.                 elseif ($row['bgimage'] != '')
  437.                 {
  438.                     if (($strImage $this->generateBase64Image($row['bgimage'], $parent)) !== false)
  439.                     {
  440.                         $return .= $lb 'background-image:url("' $strImage '");';
  441.                     }
  442.                     else
  443.                     {
  444.                         $glue = (strncmp($row['bgimage'], 'data:'5) !== && strncmp($row['bgimage'], 'http://'7) !== && strncmp($row['bgimage'], 'https://'8) !== && strncmp($row['bgimage'], '/'1) !== 0) ? $strGlue '';
  445.                         $return .= $lb 'background-image:url("' $glue $row['bgimage'] . '");';
  446.                     }
  447.                 }
  448.                 // Background position
  449.                 if ($row['bgposition'] != '')
  450.                 {
  451.                     $return .= $lb 'background-position:' $row['bgposition'] . ';';
  452.                 }
  453.                 // Background repeat
  454.                 if ($row['bgrepeat'] != '')
  455.                 {
  456.                     $return .= $lb 'background-repeat:' $row['bgrepeat'] . ';';
  457.                 }
  458.             }
  459.             // Background gradient
  460.             if ($row['gradientAngle'] != '' && $row['gradientColors'] != '')
  461.             {
  462.                 $row['gradientColors'] = StringUtil::deserialize($row['gradientColors']);
  463.                 if (\is_array($row['gradientColors']) && \count(array_filter($row['gradientColors'])) > 0)
  464.                 {
  465.                     $bgImage '';
  466.                     // CSS3 PIE only supports -pie-background, so if there is a background image, include it here, too.
  467.                     if ($row['bgimage'] != '' && $row['bgposition'] != '' && $row['bgrepeat'] != '')
  468.                     {
  469.                         $glue = (strncmp($row['bgimage'], 'data:'5) !== && strncmp($row['bgimage'], 'http://'7) !== && strncmp($row['bgimage'], 'https://'8) !== && strncmp($row['bgimage'], '/'1) !== 0) ? $strGlue '';
  470.                         $bgImage 'url("' $glue $row['bgimage'] . '") ' $row['bgposition'] . ' ' $row['bgrepeat'] . ',';
  471.                     }
  472.                     // Default starting point
  473.                     if ($row['gradientAngle'] == '')
  474.                     {
  475.                         $row['gradientAngle'] = 'to top';
  476.                     }
  477.                     $row['gradientColors'] = array_values(array_filter($row['gradientColors']));
  478.                     // Add a hashtag to the color values
  479.                     foreach ($row['gradientColors'] as $k=>$v)
  480.                     {
  481.                         $row['gradientColors'][$k] = '#' $v;
  482.                     }
  483.                     $angle '';
  484.                     // Convert the angle for the legacy commands (see #4569)
  485.                     if (strpos($row['gradientAngle'], 'deg') !== false)
  486.                     {
  487.                         $angle = (abs((int) $row['gradientAngle'] - 450) % 360) . 'deg';
  488.                     }
  489.                     else
  490.                     {
  491.                         switch ($row['gradientAngle'])
  492.                         {
  493.                             case 'to top'$angle 'bottom'; break;
  494.                             case 'to right'$angle 'left'; break;
  495.                             case 'to bottom'$angle 'top'; break;
  496.                             case 'to left'$angle 'right'; break;
  497.                             case 'to top left'$angle 'bottom right'; break;
  498.                             case 'to top right'$angle 'bottom left'; break;
  499.                             case 'to bottom left'$angle 'top right'; break;
  500.                             case 'to bottom right'$angle 'top left'; break;
  501.                         }
  502.                     }
  503.                     $colors implode(','$row['gradientColors']);
  504.                     $legacy $angle ',' $colors;
  505.                     $gradient $row['gradientAngle'] . ',' $colors;
  506.                     $return .= $lb 'background:' $bgImage '-moz-linear-gradient(' $legacy ');';
  507.                     $return .= $lb 'background:' $bgImage '-webkit-linear-gradient(' $legacy ');';
  508.                     $return .= $lb 'background:' $bgImage '-o-linear-gradient(' $legacy ');';
  509.                     $return .= $lb 'background:' $bgImage '-ms-linear-gradient(' $legacy ');';
  510.                     $return .= $lb 'background:' $bgImage 'linear-gradient(' $gradient ');';
  511.                     $return .= $lb '-pie-background:' $bgImage 'linear-gradient(' $legacy ');';
  512.                 }
  513.             }
  514.             // Box shadow
  515.             if ($row['shadowsize'] != '')
  516.             {
  517.                 $shColor StringUtil::deserialize($row['shadowcolor'], true);
  518.                 $row['shadowsize'] = StringUtil::deserialize($row['shadowsize']);
  519.                 if (\is_array($row['shadowsize']) && $row['shadowsize']['top'] != '' && $row['shadowsize']['right'] != '')
  520.                 {
  521.                     $offsetx $row['shadowsize']['top'];
  522.                     $offsety $row['shadowsize']['right'];
  523.                     $blursize $row['shadowsize']['bottom'];
  524.                     $radius $row['shadowsize']['left'];
  525.                     $shadow $offsetx . (($offsetx === '0') ? '' $row['shadowsize']['unit']);
  526.                     $shadow .= ' ' $offsety . (($offsety === '0') ? '' $row['shadowsize']['unit']);
  527.                     if ($blursize != '')
  528.                     {
  529.                         $shadow .= ' ' $blursize . (($blursize === '0') ? '' $row['shadowsize']['unit']);
  530.                     }
  531.                     if ($radius != '')
  532.                     {
  533.                         $shadow .= ' ' $radius . (($radius === '0') ? '' $row['shadowsize']['unit']);
  534.                     }
  535.                     if ($shColor[0] != '')
  536.                     {
  537.                         $shadow .= ' ' $this->compileColor($shColor$blnWriteToFile$vars);
  538.                     }
  539.                     $shadow .= ';';
  540.                     // Prefix required in Safari <= 5 and Android
  541.                     $return .= $lb '-webkit-box-shadow:' $shadow;
  542.                     $return .= $lb 'box-shadow:' $shadow;
  543.                 }
  544.             }
  545.         }
  546.         // Border
  547.         if ($row['border'])
  548.         {
  549.             $bdColor StringUtil::deserialize($row['bordercolor'], true);
  550.             $row['borderwidth'] = StringUtil::deserialize($row['borderwidth']);
  551.             // Border width
  552.             if (\is_array($row['borderwidth']))
  553.             {
  554.                 $top $row['borderwidth']['top'] ?? '';
  555.                 $right $row['borderwidth']['right'] ?? '';
  556.                 $bottom $row['borderwidth']['bottom'] ?? '';
  557.                 $left $row['borderwidth']['left'] ?? '';
  558.                 // Try to shorten the definition
  559.                 if ($top != '' && $right != '' && $bottom != '' && $left != '' && $top == $right && $top == $bottom && $top == $left)
  560.                 {
  561.                     $return .= $lb 'border:' $top $row['borderwidth']['unit'] . (($row['borderstyle'] != '') ? ' ' $row['borderstyle'] : '') . (($bdColor[0] != '') ? ' ' $this->compileColor($bdColor$blnWriteToFile$vars) : '') . ';';
  562.                 }
  563.                 elseif ($top != '' && $right != '' && $bottom != '' && $left != '' && $top == $bottom && $left == $right)
  564.                 {
  565.                     $return .= $lb 'border-width:' $top $row['borderwidth']['unit'] . ' ' $right $row['borderwidth']['unit'] . ';';
  566.                     if ($row['borderstyle'] != '')
  567.                     {
  568.                         $return .= $lb 'border-style:' $row['borderstyle'] . ';';
  569.                     }
  570.                     if ($bdColor[0] != '')
  571.                     {
  572.                         $return .= $lb 'border-color:' $this->compileColor($bdColor$blnWriteToFile$vars) . ';';
  573.                     }
  574.                 }
  575.                 elseif ($top == '' && $right == '' && $bottom == '' && $left == '')
  576.                 {
  577.                     if ($row['borderstyle'] != '')
  578.                     {
  579.                         $return .= $lb 'border-style:' $row['borderstyle'] . ';';
  580.                     }
  581.                     if ($bdColor[0] != '')
  582.                     {
  583.                         $return .= $lb 'border-color:' $this->compileColor($bdColor$blnWriteToFile$vars) . ';';
  584.                     }
  585.                 }
  586.                 else
  587.                 {
  588.                     $arrDir compact('top''right''bottom''left');
  589.                     foreach ($arrDir as $k=>$v)
  590.                     {
  591.                         if ($v != '')
  592.                         {
  593.                             $return .= $lb 'border-' $k ':' $v $row['borderwidth']['unit'] . (($row['borderstyle'] != '') ? ' ' $row['borderstyle'] : '') . (($bdColor[0] != '') ? ' ' $this->compileColor($bdColor$blnWriteToFile$vars) : '') . ';';
  594.                         }
  595.                     }
  596.                 }
  597.             }
  598.             else
  599.             {
  600.                 if ($row['borderstyle'] != '')
  601.                 {
  602.                     $return .= $lb 'border-style:' $row['borderstyle'] . ';';
  603.                 }
  604.                 if ($bdColor[0] != '')
  605.                 {
  606.                     $return .= $lb 'border-color:' $this->compileColor($bdColor$blnWriteToFile$vars) . ';';
  607.                 }
  608.             }
  609.             // Border radius
  610.             if ($row['borderradius'] != '')
  611.             {
  612.                 $row['borderradius'] = StringUtil::deserialize($row['borderradius']);
  613.                 if (\is_array($row['borderradius']) && ($row['borderradius']['top'] != '' || $row['borderradius']['right'] != '' || $row['borderradius']['bottom'] != '' || $row['borderradius']['left'] != ''))
  614.                 {
  615.                     $top $row['borderradius']['top'];
  616.                     $right $row['borderradius']['right'];
  617.                     $bottom $row['borderradius']['bottom'];
  618.                     $left $row['borderradius']['left'];
  619.                     $borderradius '';
  620.                     // Try to shorten the definition
  621.                     if ($top != '' && $right != '' && $bottom != '' && $left != '')
  622.                     {
  623.                         if ($top == $right && $top == $bottom && $top == $left)
  624.                         {
  625.                             $borderradius $top . (($top === '0') ? '' $row['borderradius']['unit']) . ';';
  626.                         }
  627.                         elseif ($top == $bottom && $right == $left)
  628.                         {
  629.                             $borderradius $top . (($top === '0') ? '' $row['borderradius']['unit']) . ' ' $right . (($right === '0') ? '' $row['borderradius']['unit']) . ';';
  630.                         }
  631.                         elseif ($top != $bottom && $right == $left)
  632.                         {
  633.                             $borderradius $top . (($top === '0') ? '' $row['borderradius']['unit']) . ' ' $right . (($right === '0') ? '' $row['borderradius']['unit']) . ' ' $bottom . (($bottom === '0') ? '' $row['borderradius']['unit']) . ';';
  634.                         }
  635.                         else
  636.                         {
  637.                             $borderradius .= $top . (($top === '0') ? '' $row['borderradius']['unit']) . ' ' $right . (($right === '0') ? '' $row['borderradius']['unit']) . ' ' $bottom . (($bottom === '0') ? '' $row['borderradius']['unit']) . ' ' $left . (($left === '0') ? '' $row['borderradius']['unit']) . ';';
  638.                         }
  639.                         $return .= $lb 'border-radius:' $borderradius;
  640.                     }
  641.                     else
  642.                     {
  643.                         $arrDir = array('top-left'=>$top'top-right'=>$right'bottom-right'=>$bottom'bottom-left'=>$left);
  644.                         foreach ($arrDir as $k=>$v)
  645.                         {
  646.                             if ($v != '')
  647.                             {
  648.                                 $return .= $lb 'border-' $k '-radius:' $v . (($v === '0') ? '' $row['borderradius']['unit']) . ';';
  649.                             }
  650.                         }
  651.                     }
  652.                 }
  653.             }
  654.             // Border collapse
  655.             if ($row['bordercollapse'] != '')
  656.             {
  657.                 $return .= $lb 'border-collapse:' $row['bordercollapse'] . ';';
  658.             }
  659.             // Border spacing
  660.             $row['borderspacing'] = StringUtil::deserialize($row['borderspacing']);
  661.             if (isset($row['borderspacing']['value']) && $row['borderspacing']['value'] != '')
  662.             {
  663.                 $return .= $lb 'border-spacing:' $row['borderspacing']['value'] . $row['borderspacing']['unit'] . ';';
  664.             }
  665.         }
  666.         // Font
  667.         if ($row['font'])
  668.         {
  669.             $row['fontsize'] = StringUtil::deserialize($row['fontsize']);
  670.             $row['lineheight'] = StringUtil::deserialize($row['lineheight']);
  671.             $row['fontfamily'] = str_replace(', '','$row['fontfamily']);
  672.             // Try to shorten the definition
  673.             if ($row['fontfamily'] != '' && $row['fontfamily'] != 'inherit' && isset($row['fontsize']['value']) && $row['fontsize']['value'] != '' && $row['fontsize']['value'] != 'inherit')
  674.             {
  675.                 $return .= $lb 'font:' $row['fontsize']['value'] . $row['fontsize']['unit'] . ((isset($row['lineheight']['value']) && $row['lineheight']['value'] != '') ? '/' $row['lineheight']['value'] . $row['lineheight']['unit'] : '') . ' ' $row['fontfamily'] . ';';
  676.             }
  677.             else
  678.             {
  679.                 // Font family
  680.                 if ($row['fontfamily'] != '')
  681.                 {
  682.                     $return .= $lb 'font-family:' $row['fontfamily'] . ';';
  683.                 }
  684.                 // Font size
  685.                 if (isset($row['fontsize']['value']) && $row['fontsize']['value'] != '')
  686.                 {
  687.                     $return .= $lb 'font-size:' $row['fontsize']['value'] . $row['fontsize']['unit'] . ';';
  688.                 }
  689.                 // Line height
  690.                 if (isset($row['lineheight']['value']) && $row['lineheight']['value'] != '')
  691.                 {
  692.                     $return .= $lb 'line-height:' $row['lineheight']['value'] . $row['lineheight']['unit'] . ';';
  693.                 }
  694.             }
  695.             // Font style
  696.             $row['fontstyle'] = StringUtil::deserialize($row['fontstyle']);
  697.             if (\is_array($row['fontstyle']))
  698.             {
  699.                 if (\in_array('bold'$row['fontstyle']))
  700.                 {
  701.                     $return .= $lb 'font-weight:bold;';
  702.                 }
  703.                 if (\in_array('italic'$row['fontstyle']))
  704.                 {
  705.                     $return .= $lb 'font-style:italic;';
  706.                 }
  707.                 if (\in_array('normal'$row['fontstyle']))
  708.                 {
  709.                     $return .= $lb 'font-weight:normal;';
  710.                 }
  711.                 if (\in_array('underline'$row['fontstyle']))
  712.                 {
  713.                     $return .= $lb 'text-decoration:underline;';
  714.                 }
  715.                 if (\in_array('line-through'$row['fontstyle']))
  716.                 {
  717.                     $return .= $lb 'text-decoration:line-through;';
  718.                 }
  719.                 if (\in_array('overline'$row['fontstyle']))
  720.                 {
  721.                     $return .= $lb 'text-decoration:overline;';
  722.                 }
  723.                 if (\in_array('notUnderlined'$row['fontstyle']))
  724.                 {
  725.                     $return .= $lb 'text-decoration:none;';
  726.                 }
  727.                 if (\in_array('small-caps'$row['fontstyle']))
  728.                 {
  729.                     $return .= $lb 'font-variant:small-caps;';
  730.                 }
  731.             }
  732.             $fnColor StringUtil::deserialize($row['fontcolor'], true);
  733.             // Font color
  734.             if (!empty($fnColor[0]))
  735.             {
  736.                 $return .= $lb 'color:' $this->compileColor($fnColor$blnWriteToFile$vars) . ';';
  737.             }
  738.             // Text transform
  739.             if ($row['texttransform'] != '')
  740.             {
  741.                 $return .= $lb 'text-transform:' $row['texttransform'] . ';';
  742.             }
  743.             // Text indent
  744.             $row['textindent'] = StringUtil::deserialize($row['textindent']);
  745.             if (isset($row['textindent']['value']) && $row['textindent']['value'] != '')
  746.             {
  747.                 $return .= $lb 'text-indent:' $row['textindent']['value'] . $row['textindent']['unit'] . ';';
  748.             }
  749.             // Letter spacing
  750.             $row['letterspacing'] = StringUtil::deserialize($row['letterspacing']);
  751.             if (isset($row['letterspacing']['value']) && $row['letterspacing']['value'] != '')
  752.             {
  753.                 $return .= $lb 'letter-spacing:' $row['letterspacing']['value'] . $row['letterspacing']['unit'] . ';';
  754.             }
  755.             // Word spacing
  756.             $row['wordspacing'] = StringUtil::deserialize($row['wordspacing']);
  757.             if (isset($row['wordspacing']['value']) && $row['wordspacing']['value'] != '')
  758.             {
  759.                 $return .= $lb 'word-spacing:' $row['wordspacing']['value'] . $row['wordspacing']['unit'] . ';';
  760.             }
  761.         }
  762.         // List
  763.         if ($row['list'])
  764.         {
  765.             // List bullet
  766.             if ($row['liststyletype'] != '')
  767.             {
  768.                 $return .= $lb 'list-style-type:' $row['liststyletype'] . ';';
  769.             }
  770.             // List image
  771.             if ($row['liststyleimage'] == 'none')
  772.             {
  773.                 $return .= $lb 'list-style-image:none;';
  774.             }
  775.             elseif ($row['liststyleimage'] != '')
  776.             {
  777.                 if (($strImage $this->generateBase64Image($row['liststyleimage'], $parent)) !== false)
  778.                 {
  779.                     $return .= $lb 'list-style-image:url("' $strImage '");';
  780.                 }
  781.                 else
  782.                 {
  783.                     $glue = (strncmp($row['liststyleimage'], 'data:'5) !== && strncmp($row['liststyleimage'], 'http://'7) !== && strncmp($row['liststyleimage'], 'https://'8) !== && strncmp($row['liststyleimage'], '/'1) !== 0) ? $strGlue '';
  784.                     $return .= $lb 'list-style-image:url("' $glue $row['liststyleimage'] . '");';
  785.                 }
  786.             }
  787.         }
  788.         // Optimize floating-point numbers (see #6634)
  789.         $return preg_replace('/([^0-9.+-])0\.([0-9]+)/''$1.$2'$return);
  790.         // Custom code
  791.         if ($row['own'] != '')
  792.         {
  793.             $own trim(StringUtil::decodeEntities($row['own']));
  794.             $own preg_replace('/url\("(?!data:|\/)/''url("' $strGlue$own);
  795.             $own preg_split('/[\n\r]+/'$own);
  796.             $own implode(($blnWriteToFile '' $lb), $own);
  797.             $return .= $lb . ((!$blnWriteToFile && !$export) ? StringUtil::specialchars($own) : $own);
  798.         }
  799.         // Allow custom definitions
  800.         if (isset($GLOBALS['TL_HOOKS']['compileDefinition']) && \is_array($GLOBALS['TL_HOOKS']['compileDefinition']))
  801.         {
  802.             foreach ($GLOBALS['TL_HOOKS']['compileDefinition'] as $callback)
  803.             {
  804.                 $this->import($callback[0]);
  805.                 $strTemp $this->{$callback[0]}->{$callback[1]}($row$blnWriteToFile$vars$parent);
  806.                 if ($strTemp != '')
  807.                 {
  808.                     $return .= $lb $strTemp;
  809.                 }
  810.             }
  811.         }
  812.         // Close the format definition
  813.         if ($blnWriteToFile)
  814.         {
  815.             // Remove the last semicolon (;) before the closing bracket
  816.             if (substr($return, -1) == ';')
  817.             {
  818.                 $return substr($return0, -1);
  819.             }
  820.             $return .= '}';
  821.         }
  822.         elseif ($export)
  823.         {
  824.             $return .= "\n}\n";
  825.         }
  826.         else
  827.         {
  828.             $return .= "\n}</pre>\n";
  829.         }
  830.         // Replace global variables
  831.         if (!empty($vars) && strpos($return'$') !== false)
  832.         {
  833.             $return str_replace(array_keys($vars), $vars$return);
  834.         }
  835.         // Replace insert tags (see #5512)
  836.         return System::getContainer()->get('contao.insert_tag.parser')->replaceInline($return);
  837.     }
  838.     /**
  839.      * Compile a color value and return a hex or rgba color
  840.      *
  841.      * @param mixed   $color
  842.      * @param boolean $blnWriteToFile
  843.      * @param array   $vars
  844.      *
  845.      * @return string
  846.      */
  847.     protected function compileColor($color$blnWriteToFile=false$vars=array())
  848.     {
  849.         if (!\is_array($color))
  850.         {
  851.             return '#' $this->shortenHexColor($color);
  852.         }
  853.         if (empty($color[1]))
  854.         {
  855.             return '#' $this->shortenHexColor($color[0]);
  856.         }
  857.         return 'rgba(' implode(','$this->convertHexColor($color[0], $blnWriteToFile$vars)) . ',' . ($color[1] / 100) . ')';
  858.     }
  859.     /**
  860.      * Try to shorten a hex color
  861.      *
  862.      * @param string $color
  863.      *
  864.      * @return string
  865.      */
  866.     protected function shortenHexColor($color)
  867.     {
  868.         if (\strlen($color) == && $color[0] == $color[1] && $color[2] == $color[3] && $color[4] == $color[5])
  869.         {
  870.             return $color[0] . $color[2] . $color[4];
  871.         }
  872.         return $color;
  873.     }
  874.     /**
  875.      * Convert hex colors to rgb
  876.      *
  877.      * @param string  $color
  878.      * @param boolean $blnWriteToFile
  879.      * @param array   $vars
  880.      *
  881.      * @return array
  882.      *
  883.      * @see http://de3.php.net/manual/de/function.hexdec.php#99478
  884.      */
  885.     protected function convertHexColor($color$blnWriteToFile=false$vars=array())
  886.     {
  887.         // Support global variables
  888.         if (strncmp($color'$'1) === 0)
  889.         {
  890.             if (!$blnWriteToFile)
  891.             {
  892.                 return array($color);
  893.             }
  894.             $color str_replace(array_keys($vars), $vars$color);
  895.         }
  896.         $rgb = array();
  897.         // Try to convert using bitwise operation
  898.         if (\strlen($color) == 6)
  899.         {
  900.             $dec hexdec($color);
  901.             $rgb['red'] = 0xFF & ($dec >> 0x10);
  902.             $rgb['green'] = 0xFF & ($dec >> 0x8);
  903.             $rgb['blue'] = 0xFF $dec;
  904.         }
  905.         // Shorthand notation
  906.         elseif (\strlen($color) == 3)
  907.         {
  908.             $rgb['red'] = hexdec(str_repeat(substr($color01), 2));
  909.             $rgb['green'] = hexdec(str_repeat(substr($color11), 2));
  910.             $rgb['blue'] = hexdec(str_repeat(substr($color21), 2));
  911.         }
  912.         return $rgb;
  913.     }
  914.     /**
  915.      * Return a form to choose an existing style sheet and import it
  916.      *
  917.      * @return string
  918.      *
  919.      * @throws \Exception
  920.      */
  921.     public function importStyleSheet()
  922.     {
  923.         if (Input::get('key') != 'import')
  924.         {
  925.             return '';
  926.         }
  927.         $objUploader = new FileUpload();
  928.         // Import CSS
  929.         if (Input::post('FORM_SUBMIT') == 'tl_style_sheet_import')
  930.         {
  931.             $arrUploaded $objUploader->uploadTo('system/tmp');
  932.             if (empty($arrUploaded))
  933.             {
  934.                 Message::addError($GLOBALS['TL_LANG']['ERR']['all_fields']);
  935.                 $this->reload();
  936.             }
  937.             foreach ($arrUploaded as $strCssFile)
  938.             {
  939.                 // Folders cannot be imported
  940.                 if (is_dir($this->strRootDir '/' $strCssFile))
  941.                 {
  942.                     Message::addError(sprintf($GLOBALS['TL_LANG']['ERR']['importFolder'], basename($strCssFile)));
  943.                     continue;
  944.                 }
  945.                 $objFile = new File($strCssFile);
  946.                 // Check the file extension
  947.                 if ($objFile->extension != 'css')
  948.                 {
  949.                     Message::addError(sprintf($GLOBALS['TL_LANG']['ERR']['filetype'], $objFile->extension));
  950.                     continue;
  951.                 }
  952.                 // Check the file name
  953.                 $strName preg_replace('/\.css$/i'''basename($strCssFile));
  954.                 $strName $this->checkStyleSheetName($strName);
  955.                 // Create the new style sheet
  956.                 $objStyleSheet $this->Database->prepare("INSERT INTO tl_style_sheet (pid, tstamp, name, media) VALUES (?, ?, ?, ?)")
  957.                                                 ->execute(Input::get('id'), time(), $strName, array('all'));
  958.                 $insertId $objStyleSheet->insertId;
  959.                 if (!is_numeric($insertId) || $insertId 0)
  960.                 {
  961.                     throw new \Exception('Invalid insert ID');
  962.                 }
  963.                 // Read the file and remove carriage returns
  964.                 $strFile $objFile->getContent();
  965.                 $strFile str_replace("\r"''$strFile);
  966.                 $arrTokens   = array();
  967.                 $strBuffer   '';
  968.                 $intSorting  0;
  969.                 $strComment  '';
  970.                 $strCategory '';
  971.                 $intLength   \strlen($strFile);
  972.                 // Tokenize
  973.                 for ($i=0$i<$intLength$i++)
  974.                 {
  975.                     $char $strFile[$i];
  976.                     // Whitespace
  977.                     if ($char == '' || $char == "\n" || $char == "\t")
  978.                     {
  979.                         // Ignore
  980.                     }
  981.                     // Comment
  982.                     elseif ($char == '/')
  983.                     {
  984.                         if ($strFile[$i+1] == '*')
  985.                         {
  986.                             while ($i<$intLength)
  987.                             {
  988.                                 $strBuffer .= $strFile[$i++];
  989.                                 if ($strFile[$i] == '/' && $strFile[$i-1] == '*')
  990.                                 {
  991.                                     $arrTokens[] = array
  992.                                     (
  993.                                         'type'    => 'comment',
  994.                                         'content' => $strBuffer $strFile[$i]
  995.                                     );
  996.                                     $strBuffer '';
  997.                                     break;
  998.                                 }
  999.                             }
  1000.                         }
  1001.                     }
  1002.                     // At block
  1003.                     elseif ($char == '@')
  1004.                     {
  1005.                         $intLevel 0;
  1006.                         $strSelector '';
  1007.                         while ($i<$intLength)
  1008.                         {
  1009.                             $strBuffer .= $strFile[$i++];
  1010.                             if ($strFile[$i] == '{')
  1011.                             {
  1012.                                 if (++$intLevel == 1)
  1013.                                 {
  1014.                                     ++$i;
  1015.                                     $strSelector $strBuffer;
  1016.                                     $strBuffer '';
  1017.                                 }
  1018.                             }
  1019.                             elseif ($strFile[$i] == '}')
  1020.                             {
  1021.                                 if (--$intLevel == 0)
  1022.                                 {
  1023.                                     $arrTokens[] = array
  1024.                                     (
  1025.                                         'type'     => 'atblock',
  1026.                                         'selector' => $strSelector,
  1027.                                         'content'  => $strBuffer
  1028.                                     );
  1029.                                     $strBuffer '';
  1030.                                     break;
  1031.                                 }
  1032.                             }
  1033.                         }
  1034.                     }
  1035.                     // Regular block
  1036.                     else
  1037.                     {
  1038.                         $strSelector '';
  1039.                         while ($i<$intLength)
  1040.                         {
  1041.                             $strBuffer .= $strFile[$i++];
  1042.                             if ($strFile[$i] == '{')
  1043.                             {
  1044.                                 ++$i;
  1045.                                 $strSelector $strBuffer;
  1046.                                 $strBuffer '';
  1047.                             }
  1048.                             elseif ($strFile[$i] == '}')
  1049.                             {
  1050.                                 $arrTokens[] = array
  1051.                                 (
  1052.                                     'type'     => 'block',
  1053.                                     'selector' => $strSelector,
  1054.                                     'content'  => $strBuffer
  1055.                                 );
  1056.                                 $strBuffer '';
  1057.                                 break;
  1058.                             }
  1059.                         }
  1060.                     }
  1061.                 }
  1062.                 foreach ($arrTokens as $arrToken)
  1063.                 {
  1064.                     // Comments
  1065.                     if ($arrToken['type'] == 'comment')
  1066.                     {
  1067.                         // Category (comments start with /** and contain only one line)
  1068.                         if (strncmp($arrToken['content'], '/**'3) === && substr_count($arrToken['content'], "\n") == 2)
  1069.                         {
  1070.                             $strCategory trim(str_replace(array('/*''*/''*'), ''$arrToken['content']));
  1071.                         }
  1072.                         // Declaration comment
  1073.                         elseif (strpos($arrToken['content'], "\n") === false)
  1074.                         {
  1075.                             $strComment trim(str_replace(array('/*''*/''*'), ''$arrToken['content']));
  1076.                         }
  1077.                     }
  1078.                     // At blocks like @media or @-webkit-keyframe
  1079.                     elseif ($arrToken['type'] == 'atblock')
  1080.                     {
  1081.                         $arrSet = array
  1082.                         (
  1083.                             'pid'        => $insertId,
  1084.                             'category'   => $strCategory,
  1085.                             'comment'    => $strComment,
  1086.                             'sorting'    => $intSorting += 128,
  1087.                             'selector'   => trim($arrToken['selector']),
  1088.                             'own'        => $arrToken['content']
  1089.                         );
  1090.                         $this->Database->prepare("INSERT INTO tl_style %s")->set($arrSet)->execute();
  1091.                         $strComment '';
  1092.                     }
  1093.                     // Regular blocks
  1094.                     else
  1095.                     {
  1096.                         $arrDefinition = array
  1097.                         (
  1098.                             'pid'        => $insertId,
  1099.                             'category'   => $strCategory,
  1100.                             'comment'    => $strComment,
  1101.                             'sorting'    => $intSorting += 128,
  1102.                             'selector'   => trim($arrToken['selector']),
  1103.                             'attributes' => $arrToken['content']
  1104.                         );
  1105.                         $this->createDefinition($arrDefinition);
  1106.                         $strComment '';
  1107.                     }
  1108.                 }
  1109.                 // Write the style sheet
  1110.                 $this->updateStyleSheet($insertId);
  1111.                 // Notify the user
  1112.                 if ($strName '.css' != basename($strCssFile))
  1113.                 {
  1114.                     Message::addInfo(sprintf($GLOBALS['TL_LANG']['tl_style_sheet']['css_renamed'], basename($strCssFile), $strName '.css'));
  1115.                 }
  1116.                 else
  1117.                 {
  1118.                     Message::addConfirmation(sprintf($GLOBALS['TL_LANG']['tl_style_sheet']['css_imported'], $strName '.css'));
  1119.                 }
  1120.             }
  1121.             // Redirect
  1122.             $this->redirect(str_replace('&key=import'''Environment::get('request')));
  1123.         }
  1124.         // Return form
  1125.         return Message::generate() . '
  1126. <div id="tl_buttons">
  1127. <a href="' StringUtil::ampersand(str_replace('&key=import'''Environment::get('request'))) . '" class="header_back" title="' StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['backBTTitle']) . '" accesskey="b">' $GLOBALS['TL_LANG']['MSC']['backBT'] . '</a>
  1128. </div>
  1129. <form id="tl_style_sheet_import" class="tl_form tl_edit_form" method="post" enctype="multipart/form-data">
  1130. <div class="tl_formbody_edit">
  1131. <input type="hidden" name="FORM_SUBMIT" value="tl_style_sheet_import">
  1132. <input type="hidden" name="REQUEST_TOKEN" value="' REQUEST_TOKEN '">
  1133. <input type="hidden" name="MAX_FILE_SIZE" value="' Config::get('maxFileSize') . '">
  1134. <div class="tl_tbox">
  1135.   <div class="widget">
  1136.     <h3>' $GLOBALS['TL_LANG']['tl_style_sheet']['source'][0] . '</h3>' $objUploader->generateMarkup() . (isset($GLOBALS['TL_LANG']['tl_style_sheet']['source'][1]) ? '
  1137.     <p class="tl_help tl_tip">' $GLOBALS['TL_LANG']['tl_style_sheet']['source'][1] . '</p>' '') . '
  1138.   </div>
  1139. </div>
  1140. </div>
  1141. <div class="tl_formbody_submit">
  1142. <div class="tl_submit_container">
  1143.   <button type="submit" name="save" id="save" class="tl_submit" accesskey="s">' $GLOBALS['TL_LANG']['tl_style_sheet']['import'][0] . '</button>
  1144. </div>
  1145. </div>
  1146. </form>';
  1147.     }
  1148.     /**
  1149.      * Export a style sheet
  1150.      *
  1151.      * @param DataContainer $dc
  1152.      *
  1153.      * @throws \Exception
  1154.      */
  1155.     public function exportStyleSheet(DataContainer $dc)
  1156.     {
  1157.         $objStyleSheet $this->Database->prepare("SELECT * FROM tl_style_sheet WHERE id=?")
  1158.                                         ->limit(1)
  1159.                                         ->execute($dc->id);
  1160.         if ($objStyleSheet->numRows 1)
  1161.         {
  1162.             throw new \Exception("Invalid style sheet ID $dc->id");
  1163.         }
  1164.         $vars = array();
  1165.         // Get the global theme variables
  1166.         $objTheme $this->Database->prepare("SELECT vars FROM tl_theme WHERE id=?")
  1167.                                    ->limit(1)
  1168.                                    ->execute($objStyleSheet->pid);
  1169.         if ($objTheme->vars != '' && \is_array(($tmp StringUtil::deserialize($objTheme->vars))))
  1170.         {
  1171.             foreach ($tmp as $v)
  1172.             {
  1173.                 $vars[$v['key']] = $v['value'];
  1174.             }
  1175.         }
  1176.         // Merge the global style sheet variables
  1177.         if ($objStyleSheet->vars != '' && \is_array(($tmp StringUtil::deserialize($objStyleSheet->vars))))
  1178.         {
  1179.             foreach ($tmp as $v)
  1180.             {
  1181.                 $vars[$v['key']] = $v['value'];
  1182.             }
  1183.         }
  1184.         // Sort by key length (see #3316)
  1185.         uksort($vars, static function ($a$b): int
  1186.         {
  1187.             return \strlen($b) - \strlen($a);
  1188.         });
  1189.         // Create the file
  1190.         $objFile = new File('system/tmp/' md5(uniqid(mt_rand(), true)));
  1191.         $objFile->write('');
  1192.         $blnClose false;
  1193.         // Add the media query (see #7560)
  1194.         if ($objStyleSheet->mediaQuery != '')
  1195.         {
  1196.             $objFile->append('@media ' $objStyleSheet->mediaQuery ' {');
  1197.             $blnClose true;
  1198.         }
  1199.         elseif (\is_array(($tmp StringUtil::deserialize($objStyleSheet->media))) && (\count($tmp) > || $tmp[0] != 'all'))
  1200.         {
  1201.             $objFile->append('@media ' implode(', '$tmp) . ' {');
  1202.             $blnClose true;
  1203.         }
  1204.         $objDefinitions $this->Database->prepare("SELECT * FROM tl_style WHERE pid=? AND invisible!='1' ORDER BY sorting")
  1205.                                          ->execute($objStyleSheet->id);
  1206.         // Append the definition
  1207.         while ($objDefinitions->next())
  1208.         {
  1209.             $objFile->append($this->compileDefinition($objDefinitions->row(), false$vars$objStyleSheet->row(), true), '');
  1210.         }
  1211.         // Close the media query
  1212.         if ($blnClose)
  1213.         {
  1214.             $objFile->append('}');
  1215.         }
  1216.         $objFile->close();
  1217.         $objFile->sendToBrowser($objStyleSheet->name '.css');
  1218.         $objFile->delete();
  1219.     }
  1220.     /**
  1221.      * Check the name of an imported file
  1222.      *
  1223.      * @param string $strName
  1224.      *
  1225.      * @return string
  1226.      */
  1227.     public function checkStyleSheetName($strName)
  1228.     {
  1229.         $objStyleSheet $this->Database->prepare("SELECT COUNT(*) AS count FROM tl_style_sheet WHERE name=?")
  1230.                                         ->limit(1)
  1231.                                         ->execute($strName);
  1232.         if ($objStyleSheet->count 1)
  1233.         {
  1234.             return $strName;
  1235.         }
  1236.         $chunks explode('-'$strName);
  1237.         $i = (\count($chunks) > 1) ? array_pop($chunks) : 0;
  1238.         $strName implode('-'$chunks) . '-' . ((int) $i 1);
  1239.         return $this->checkStyleSheetName($strName);
  1240.     }
  1241.     /**
  1242.      * Create a format definition and insert it into the database
  1243.      *
  1244.      * @param array $arrDefinition
  1245.      */
  1246.     protected function createDefinition($arrDefinition)
  1247.     {
  1248.         $arrSet = array
  1249.         (
  1250.             'pid'      => $arrDefinition['pid'],
  1251.             'sorting'  => $arrDefinition['sorting'],
  1252.             'tstamp'   => time(),
  1253.             'comment'  => $arrDefinition['comment'],
  1254.             'category' => $arrDefinition['category'],
  1255.             'selector' => $arrDefinition['selector']
  1256.         );
  1257.         $arrAttributes StringUtil::trimsplit(';'$arrDefinition['attributes']);
  1258.         foreach ($arrAttributes as $strDefinition)
  1259.         {
  1260.             // Skip empty definitions
  1261.             if (trim($strDefinition) == '')
  1262.             {
  1263.                 continue;
  1264.             }
  1265.             // Handle keywords, variables and functions (see #7448)
  1266.             if (strpos($strDefinition'important') !== false || strpos($strDefinition'transparent') !== false || strpos($strDefinition'inherit') !== false || strpos($strDefinition'$') !== false || strpos($strDefinition'(') !== false)
  1267.             {
  1268.                 $arrSet['own'][] = $strDefinition;
  1269.                 continue;
  1270.             }
  1271.             $arrChunks array_map('trim'explode(':'$strDefinition2));
  1272.             $strKey strtolower($arrChunks[0]);
  1273.             switch ($strKey)
  1274.             {
  1275.                 case 'width':
  1276.                 case 'height':
  1277.                     if ($arrChunks[1] == 'auto')
  1278.                     {
  1279.                         $strUnit '';
  1280.                         $varValue 'auto';
  1281.                     }
  1282.                     else
  1283.                     {
  1284.                         $strUnit preg_replace('/[^acehimnprtvwx%]/'''$arrChunks[1]);
  1285.                         $varValue preg_replace('/[^0-9.-]+/'''$arrChunks[1]);
  1286.                     }
  1287.                     $arrSet['size'] = 1;
  1288.                     $arrSet[$strKey]['value'] = $varValue;
  1289.                     $arrSet[$strKey]['unit'] = $strUnit;
  1290.                     break;
  1291.                 case 'min-width':
  1292.                 case 'min-height':
  1293.                     $strName str_replace('-'''$strKey);
  1294.                     if ($arrChunks[1] == 'inherit')
  1295.                     {
  1296.                         $strUnit '';
  1297.                         $varValue 'inherit';
  1298.                     }
  1299.                     else
  1300.                     {
  1301.                         $strUnit preg_replace('/[^acehimnprtvwx%]/'''$arrChunks[1]);
  1302.                         $varValue preg_replace('/[^0-9.-]+/'''$arrChunks[1]);
  1303.                     }
  1304.                     $arrSet['size'] = 1;
  1305.                     $arrSet[$strName]['value'] = $varValue;
  1306.                     $arrSet[$strName]['unit'] = $strUnit;
  1307.                     break;
  1308.                 case 'max-width':
  1309.                 case 'max-height':
  1310.                     $strName str_replace('-'''$strKey);
  1311.                     if ($arrChunks[1] == 'inherit' || $arrChunks[1] == 'none')
  1312.                     {
  1313.                         $strUnit '';
  1314.                         $varValue $arrChunks[1];
  1315.                     }
  1316.                     else
  1317.                     {
  1318.                         $strUnit preg_replace('/[^acehimnprtvwx%]/'''$arrChunks[1]);
  1319.                         $varValue preg_replace('/[^0-9.-]+/'''$arrChunks[1]);
  1320.                     }
  1321.                     $arrSet['size'] = 1;
  1322.                     $arrSet[$strName]['value'] = $varValue;
  1323.                     $arrSet[$strName]['unit'] = $strUnit;
  1324.                     break;
  1325.                 case 'top':
  1326.                 case 'right':
  1327.                 case 'bottom':
  1328.                 case 'left':
  1329.                     if ($arrChunks[1] == 'auto')
  1330.                     {
  1331.                         $strUnit '';
  1332.                         $varValue 'auto';
  1333.                     }
  1334.                     elseif (isset($arrSet['trbl']['unit']))
  1335.                     {
  1336.                         $arrSet['own'][] = $strDefinition;
  1337.                         break;
  1338.                     }
  1339.                     else
  1340.                     {
  1341.                         $strUnit preg_replace('/[^acehimnprtvwx%]/'''$arrChunks[1]);
  1342.                         $varValue preg_replace('/[^0-9.-]+/'''$arrChunks[1]);
  1343.                     }
  1344.                     $arrSet['positioning'] = 1;
  1345.                     $arrSet['trbl'][$strKey] = $varValue;
  1346.                     if ($strUnit != '')
  1347.                     {
  1348.                         $arrSet['trbl']['unit'] = $strUnit;
  1349.                     }
  1350.                     break;
  1351.                 case 'position':
  1352.                 case 'overflow':
  1353.                 case 'clear':
  1354.                 case 'display':
  1355.                     $arrSet['positioning'] = 1;
  1356.                     $arrSet[$strKey] = $arrChunks[1];
  1357.                     break;
  1358.                 case 'float':
  1359.                     $arrSet['positioning'] = 1;
  1360.                     $arrSet['floating'] = $arrChunks[1];
  1361.                     break;
  1362.                 case 'margin':
  1363.                 case 'padding':
  1364.                     $arrSet['alignment'] = 1;
  1365.                     $arrTRBL preg_split('/\s+/'$arrChunks[1]);
  1366.                     $arrUnits = array();
  1367.                     switch (\count($arrTRBL))
  1368.                     {
  1369.                         case 1:
  1370.                             if ($arrTRBL[0] == 'auto')
  1371.                             {
  1372.                                 $strUnit '';
  1373.                                 $varValue 'auto';
  1374.                             }
  1375.                             else
  1376.                             {
  1377.                                 $strUnit preg_replace('/[^acehimnprtvwx%]/'''$arrTRBL[0]);
  1378.                                 $varValue preg_replace('/[^0-9.-]+/'''$arrTRBL[0]);
  1379.                             }
  1380.                             $arrSet[$strKey] = array
  1381.                             (
  1382.                                 'top' => $varValue,
  1383.                                 'right' => $varValue,
  1384.                                 'bottom' => $varValue,
  1385.                                 'left' => $varValue,
  1386.                                 'unit' => $strUnit
  1387.                             );
  1388.                             break;
  1389.                         case 2:
  1390.                             if ($arrTRBL[0] == 'auto')
  1391.                             {
  1392.                                 $varValue_1 'auto';
  1393.                             }
  1394.                             else
  1395.                             {
  1396.                                 $arrUnits[] = preg_replace('/[^acehimnprtvwx%]/'''$arrTRBL[0]);
  1397.                                 $varValue_1 preg_replace('/[^0-9.-]+/'''$arrTRBL[0]);
  1398.                             }
  1399.                             if ($arrTRBL[1] == 'auto')
  1400.                             {
  1401.                                 $varValue_2 'auto';
  1402.                             }
  1403.                             else
  1404.                             {
  1405.                                 $arrUnits[] = preg_replace('/[^acehimnprtvwx%]/'''$arrTRBL[1]);
  1406.                                 $varValue_2 preg_replace('/[^0-9.-]+/'''$arrTRBL[1]);
  1407.                             }
  1408.                             // Move to custom section if there are different units
  1409.                             if (\count(array_filter(array_unique($arrUnits))) > 1)
  1410.                             {
  1411.                                 $arrSet['alignment'] = '';
  1412.                                 $arrSet['own'][] = $strDefinition;
  1413.                                 break;
  1414.                             }
  1415.                             $arrSet[$strKey] = array
  1416.                             (
  1417.                                 'top' => $varValue_1,
  1418.                                 'right' => $varValue_2,
  1419.                                 'bottom' => $varValue_1,
  1420.                                 'left' => $varValue_2,
  1421.                                 'unit' => ''
  1422.                             );
  1423.                             // Overwrite the unit
  1424.                             foreach ($arrUnits as $strUnit)
  1425.                             {
  1426.                                 if ($strUnit != '')
  1427.                                 {
  1428.                                     $arrSet[$strKey]['unit'] = $strUnit;
  1429.                                     break;
  1430.                                 }
  1431.                             }
  1432.                             break;
  1433.                         case 3:
  1434.                             if ($arrTRBL[0] == 'auto')
  1435.                             {
  1436.                                 $varValue_1 'auto';
  1437.                             }
  1438.                             else
  1439.                             {
  1440.                                 $arrUnits[] = preg_replace('/[^acehimnprtvwx%]/'''$arrTRBL[0]);
  1441.                                 $varValue_1 preg_replace('/[^0-9.-]+/'''$arrTRBL[0]);
  1442.                             }
  1443.                             if ($arrTRBL[1] == 'auto')
  1444.                             {
  1445.                                 $varValue_2 'auto';
  1446.                             }
  1447.                             else
  1448.                             {
  1449.                                 $arrUnits[] = preg_replace('/[^acehimnprtvwx%]/'''$arrTRBL[1]);
  1450.                                 $varValue_2 preg_replace('/[^0-9.-]+/'''$arrTRBL[1]);
  1451.                             }
  1452.                             if ($arrTRBL[2] == 'auto')
  1453.                             {
  1454.                                 $varValue_3 'auto';
  1455.                             }
  1456.                             else
  1457.                             {
  1458.                                 $arrUnits[] = preg_replace('/[^acehimnprtvwx%]/'''$arrTRBL[2]);
  1459.                                 $varValue_3 preg_replace('/[^0-9.-]+/'''$arrTRBL[2]);
  1460.                             }
  1461.                             // Move to custom section if there are different units
  1462.                             if (\count(array_filter(array_unique($arrUnits))) > 1)
  1463.                             {
  1464.                                 $arrSet['alignment'] = '';
  1465.                                 $arrSet['own'][] = $strDefinition;
  1466.                                 break;
  1467.                             }
  1468.                             $arrSet[$strKey] = array
  1469.                             (
  1470.                                 'top' => $varValue_1,
  1471.                                 'right' => $varValue_2,
  1472.                                 'bottom' => $varValue_3,
  1473.                                 'left' => $varValue_2,
  1474.                                 'unit' => ''
  1475.                             );
  1476.                             // Overwrite the unit
  1477.                             foreach ($arrUnits as $strUnit)
  1478.                             {
  1479.                                 if ($strUnit != '')
  1480.                                 {
  1481.                                     $arrSet[$strKey]['unit'] = $strUnit;
  1482.                                     break;
  1483.                                 }
  1484.                             }
  1485.                             break;
  1486.                         case 4:
  1487.                             if ($arrTRBL[0] == 'auto')
  1488.                             {
  1489.                                 $varValue_1 'auto';
  1490.                             }
  1491.                             else
  1492.                             {
  1493.                                 $arrUnits[] = preg_replace('/[^acehimnprtvwx%]/'''$arrTRBL[0]);
  1494.                                 $varValue_1 preg_replace('/[^0-9.-]+/'''$arrTRBL[0]);
  1495.                             }
  1496.                             if ($arrTRBL[1] == 'auto')
  1497.                             {
  1498.                                 $varValue_2 'auto';
  1499.                             }
  1500.                             else
  1501.                             {
  1502.                                 $arrUnits[] = preg_replace('/[^acehimnprtvwx%]/'''$arrTRBL[1]);
  1503.                                 $varValue_2 preg_replace('/[^0-9.-]+/'''$arrTRBL[1]);
  1504.                             }
  1505.                             if ($arrTRBL[2] == 'auto')
  1506.                             {
  1507.                                 $varValue_3 'auto';
  1508.                             }
  1509.                             else
  1510.                             {
  1511.                                 $arrUnits[] = preg_replace('/[^acehimnprtvwx%]/'''$arrTRBL[2]);
  1512.                                 $varValue_3 preg_replace('/[^0-9.-]+/'''$arrTRBL[2]);
  1513.                             }
  1514.                             if ($arrTRBL[3] == 'auto')
  1515.                             {
  1516.                                 $varValue_4 'auto';
  1517.                             }
  1518.                             else
  1519.                             {
  1520.                                 $arrUnits[] = preg_replace('/[^acehimnprtvwx%]/'''$arrTRBL[3]);
  1521.                                 $varValue_4 preg_replace('/[^0-9.-]+/'''$arrTRBL[3]);
  1522.                             }
  1523.                             // Move to custom section if there are different units
  1524.                             if (\count(array_filter(array_unique($arrUnits))) > 1)
  1525.                             {
  1526.                                 $arrSet['alignment'] = '';
  1527.                                 $arrSet['own'][] = $strDefinition;
  1528.                                 break;
  1529.                             }
  1530.                             $arrSet[$strKey] = array
  1531.                             (
  1532.                                 'top' => $varValue_1,
  1533.                                 'right' => $varValue_2,
  1534.                                 'bottom' => $varValue_3,
  1535.                                 'left' => $varValue_4,
  1536.                                 'unit' => ''
  1537.                             );
  1538.                             // Overwrite the unit
  1539.                             foreach ($arrUnits as $strUnit)
  1540.                             {
  1541.                                 if ($strUnit != '')
  1542.                                 {
  1543.                                     $arrSet[$strKey]['unit'] = $strUnit;
  1544.                                     break;
  1545.                                 }
  1546.                             }
  1547.                             break;
  1548.                     }
  1549.                     break;
  1550.                 case 'margin-top':
  1551.                 case 'margin-right':
  1552.                 case 'margin-bottom':
  1553.                 case 'margin-left':
  1554.                     $arrSet['alignment'] = 1;
  1555.                     $strName str_replace('margin-'''$strKey);
  1556.                     if ($arrChunks[1] == 'auto')
  1557.                     {
  1558.                         $strUnit '';
  1559.                         $varValue 'auto';
  1560.                     }
  1561.                     else
  1562.                     {
  1563.                         $strUnit preg_replace('/[^acehimnprtvwx%]/'''$arrChunks[1]);
  1564.                         $varValue preg_replace('/[^0-9.-]+/'''$arrChunks[1]);
  1565.                     }
  1566.                     $arrSet['margin'][$strName] = $varValue;
  1567.                     if (empty($arrSet['margin']['unit']))
  1568.                     {
  1569.                         $arrSet['margin']['unit'] = $strUnit;
  1570.                     }
  1571.                     break;
  1572.                 case 'padding-top':
  1573.                 case 'padding-right':
  1574.                 case 'padding-bottom':
  1575.                 case 'padding-left':
  1576.                     $arrSet['alignment'] = 1;
  1577.                     $strName str_replace('padding-'''$strKey);
  1578.                     $varValue preg_replace('/[^0-9.-]+/'''$arrChunks[1]);
  1579.                     $strUnit preg_replace('/[^acehimnprtvwx%]/'''$arrChunks[1]);
  1580.                     $arrSet['padding'][$strName] = $varValue;
  1581.                     $arrSet['padding']['unit'] = $strUnit;
  1582.                     break;
  1583.                 case 'align':
  1584.                 case 'text-align':
  1585.                 case 'vertical-align':
  1586.                 case 'white-space':
  1587.                     $arrSet['alignment'] = 1;
  1588.                     $arrSet[str_replace('-'''$strKey)] = $arrChunks[1];
  1589.                     break;
  1590.                 case 'background-color':
  1591.                     if (!preg_match('/^#[a-f0-9]+$/i'$arrChunks[1]))
  1592.                     {
  1593.                         $arrSet['own'][] = $strDefinition;
  1594.                     }
  1595.                     else
  1596.                     {
  1597.                         $arrSet['background'] = 1;
  1598.                         $arrSet['bgcolor'] = str_replace('#'''$arrChunks[1]);
  1599.                     }
  1600.                     break;
  1601.                 case 'background-image':
  1602.                     $url preg_replace('/url\(["\']?([^"\')]+)["\']?\)/i''$1'$arrChunks[1]);
  1603.                     if (strncmp($url'-'1) === 0)
  1604.                     {
  1605.                         // Ignore vendor prefixed commands
  1606.                     }
  1607.                     elseif (strncmp($url'radial-gradient'15) === 0)
  1608.                     {
  1609.                         $arrSet['own'][] = $strDefinition// radial gradients (see #4640)
  1610.                     }
  1611.                     else
  1612.                     {
  1613.                         $arrSet['background'] = 1;
  1614.                         // Handle linear gradients (see #4640)
  1615.                         if (strncmp($url'linear-gradient'15) === 0)
  1616.                         {
  1617.                             $colors StringUtil::trimsplit(','preg_replace('/linear-gradient ?\(([^)]+)\)/''$1'$url));
  1618.                             $arrSet['gradientAngle'] = array_shift($colors);
  1619.                             $arrSet['gradientColors'] = serialize($colors);
  1620.                         }
  1621.                         else
  1622.                         {
  1623.                             $arrSet['bgimage'] = $url;
  1624.                         }
  1625.                     }
  1626.                     break;
  1627.                 case 'background-position':
  1628.                     $arrSet['background'] = 1;
  1629.                     if (preg_match('/[0-9]+/'$arrChunks[1]))
  1630.                     {
  1631.                         $arrSet['own'][] = $strDefinition;
  1632.                     }
  1633.                     else
  1634.                     {
  1635.                         $arrSet['bgposition'] = $arrChunks[1];
  1636.                     }
  1637.                     break;
  1638.                 case 'background-repeat':
  1639.                     $arrSet['background'] = 1;
  1640.                     $arrSet['bgrepeat'] = $arrChunks[1];
  1641.                     break;
  1642.                 case 'border':
  1643.                     if ($arrChunks[1] == 'none')
  1644.                     {
  1645.                         $arrSet['own'][] = $strDefinition;
  1646.                         break;
  1647.                     }
  1648.                     $arrWSC preg_split('/\s+/'$arrChunks[1]);
  1649.                     if ($arrWSC[2] != '' && !preg_match('/^#[a-f0-9]+$/i'$arrWSC[2]))
  1650.                     {
  1651.                         $arrSet['own'][] = $strDefinition;
  1652.                         break;
  1653.                     }
  1654.                     $arrSet['border'] = 1;
  1655.                     $varValue preg_replace('/[^0-9.-]+/'''$arrWSC[0]);
  1656.                     $strUnit preg_replace('/[^acehimnprtvwx%]/'''$arrWSC[0]);
  1657.                     $arrSet['borderwidth'] = array
  1658.                     (
  1659.                         'top' => $varValue,
  1660.                         'right' => $varValue,
  1661.                         'bottom' => $varValue,
  1662.                         'left' => $varValue,
  1663.                         'unit' => $strUnit
  1664.                     );
  1665.                     if ($arrWSC[1] != '')
  1666.                     {
  1667.                         $arrSet['borderstyle'] = $arrWSC[1];
  1668.                     }
  1669.                     if ($arrWSC[2] != '')
  1670.                     {
  1671.                         $arrSet['bordercolor'] = str_replace('#'''$arrWSC[2]);
  1672.                     }
  1673.                     break;
  1674.                 case 'border-top':
  1675.                 case 'border-right':
  1676.                 case 'border-bottom':
  1677.                 case 'border-left':
  1678.                     if ($arrChunks[1] == 'none')
  1679.                     {
  1680.                         $arrSet['own'][] = $strDefinition;
  1681.                         break;
  1682.                     }
  1683.                     $arrWSC preg_split('/\s+/'$arrChunks[1]);
  1684.                     if ($arrWSC[2] != '' && !preg_match('/^#[a-f0-9]+$/i'$arrWSC[2]))
  1685.                     {
  1686.                         $arrSet['own'][] = $strDefinition;
  1687.                         break;
  1688.                     }
  1689.                     $arrSet['border'] = 1;
  1690.                     $strName str_replace('border-'''$strKey);
  1691.                     $varValue preg_replace('/[^0-9.-]+/'''$arrWSC[0]);
  1692.                     $strUnit preg_replace('/[^acehimnprtvwx%]/'''$arrWSC[0]);
  1693.                     if ((isset($arrSet['borderwidth']['unit']) && $arrSet['borderwidth']['unit'] != $strUnit) || ($arrWSC[1] != '' && isset($arrSet['borderstyle']) && $arrSet['borderstyle'] != $arrWSC[1]) || ($arrWSC[2] != '' && isset($arrSet['bordercolor']) && $arrSet['bordercolor'] != $arrWSC[2]))
  1694.                     {
  1695.                         $arrSet['own'][] = $strDefinition;
  1696.                         break;
  1697.                     }
  1698.                     $arrSet['borderwidth'][$strName] = preg_replace('/[^0-9.-]+/'''$varValue);
  1699.                     $arrSet['borderwidth']['unit'] = $strUnit;
  1700.                     if ($arrWSC[1] != '')
  1701.                     {
  1702.                         $arrSet['borderstyle'] = $arrWSC[1];
  1703.                     }
  1704.                     if ($arrWSC[2] != '')
  1705.                     {
  1706.                         $arrSet['bordercolor'] = str_replace('#'''$arrWSC[2]);
  1707.                     }
  1708.                     break;
  1709.                 case 'border-width':
  1710.                     $arrSet['border'] = 1;
  1711.                     $arrTRBL preg_split('/\s+/'$arrChunks[1]);
  1712.                     $strUnit '';
  1713.                     foreach ($arrTRBL as $v)
  1714.                     {
  1715.                         if ($v != 0)
  1716.                         {
  1717.                             $strUnit preg_replace('/[^acehimnprtvwx%]/'''$arrTRBL[0]);
  1718.                         }
  1719.                     }
  1720.                     switch (\count($arrTRBL))
  1721.                     {
  1722.                         case 1:
  1723.                             $varValue preg_replace('/[^0-9.-]+/'''$arrTRBL[0]);
  1724.                             $arrSet['borderwidth'] = array
  1725.                             (
  1726.                                 'top' => $varValue,
  1727.                                 'right' => $varValue,
  1728.                                 'bottom' => $varValue,
  1729.                                 'left' => $varValue,
  1730.                                 'unit' => $strUnit
  1731.                             );
  1732.                             break;
  1733.                         case 2:
  1734.                             $varValue_1 preg_replace('/[^0-9.-]+/'''$arrTRBL[0]);
  1735.                             $varValue_2 preg_replace('/[^0-9.-]+/'''$arrTRBL[1]);
  1736.                             $arrSet['borderwidth'] = array
  1737.                             (
  1738.                                 'top' => $varValue_1,
  1739.                                 'right' => $varValue_2,
  1740.                                 'bottom' => $varValue_1,
  1741.                                 'left' => $varValue_2,
  1742.                                 'unit' => $strUnit
  1743.                             );
  1744.                             break;
  1745.                         case 4:
  1746.                             $arrSet['borderwidth'] = array
  1747.                             (
  1748.                                 'top' => preg_replace('/[^0-9.-]+/'''$arrTRBL[0]),
  1749.                                 'right' => preg_replace('/[^0-9.-]+/'''$arrTRBL[1]),
  1750.                                 'bottom' => preg_replace('/[^0-9.-]+/'''$arrTRBL[2]),
  1751.                                 'left' => preg_replace('/[^0-9.-]+/'''$arrTRBL[3]),
  1752.                                 'unit' => $strUnit
  1753.                             );
  1754.                             break;
  1755.                     }
  1756.                     break;
  1757.                 case 'border-color':
  1758.                     if (!preg_match('/^#[a-f0-9]+$/i'$arrChunks[1]))
  1759.                     {
  1760.                         $arrSet['own'][] = $strDefinition;
  1761.                     }
  1762.                     else
  1763.                     {
  1764.                         $arrSet['border'] = 1;
  1765.                         $arrSet['bordercolor'] = str_replace('#'''$arrChunks[1]);
  1766.                     }
  1767.                     break;
  1768.                 case 'border-radius':
  1769.                     $arrSet['border'] = 1;
  1770.                     $arrTRBL preg_split('/\s+/'$arrChunks[1]);
  1771.                     $strUnit '';
  1772.                     foreach ($arrTRBL as $v)
  1773.                     {
  1774.                         if ($v != 0)
  1775.                         {
  1776.                             $strUnit preg_replace('/[^acehimnprtvwx%]/'''$arrTRBL[0]);
  1777.                         }
  1778.                     }
  1779.                     switch (\count($arrTRBL))
  1780.                     {
  1781.                         case 1:
  1782.                             $varValue preg_replace('/[^0-9.-]+/'''$arrTRBL[0]);
  1783.                             $arrSet['borderradius'] = array
  1784.                             (
  1785.                                 'top' => $varValue,
  1786.                                 'right' => $varValue,
  1787.                                 'bottom' => $varValue,
  1788.                                 'left' => $varValue,
  1789.                                 'unit' => $strUnit
  1790.                             );
  1791.                             break;
  1792.                         case 2:
  1793.                             $varValue_1 preg_replace('/[^0-9.-]+/'''$arrTRBL[0]);
  1794.                             $varValue_2 preg_replace('/[^0-9.-]+/'''$arrTRBL[1]);
  1795.                             $arrSet['borderradius'] = array
  1796.                             (
  1797.                                 'top' => $varValue_1,
  1798.                                 'right' => $varValue_2,
  1799.                                 'bottom' => $varValue_1,
  1800.                                 'left' => $varValue_2,
  1801.                                 'unit' => $strUnit
  1802.                             );
  1803.                             break;
  1804.                         case 4:
  1805.                             $arrSet['borderradius'] = array
  1806.                             (
  1807.                                 'top' => preg_replace('/[^0-9.-]+/'''$arrTRBL[0]),
  1808.                                 'right' => preg_replace('/[^0-9.-]+/'''$arrTRBL[1]),
  1809.                                 'bottom' => preg_replace('/[^0-9.-]+/'''$arrTRBL[2]),
  1810.                                 'left' => preg_replace('/[^0-9.-]+/'''$arrTRBL[3]),
  1811.                                 'unit' => $strUnit
  1812.                             );
  1813.                             break;
  1814.                     }
  1815.                     break;
  1816.                 case '-moz-border-radius':
  1817.                 case '-webkit-border-radius':
  1818.                     // Ignore
  1819.                     break;
  1820.                 case 'border-style':
  1821.                 case 'border-collapse':
  1822.                     $arrSet['border'] = 1;
  1823.                     $arrSet[str_replace('-'''$strKey)] = $arrChunks[1];
  1824.                     break;
  1825.                 case 'border-spacing':
  1826.                     $arrSet['border'] = 1;
  1827.                     $arrSet['borderspacing'] = array
  1828.                     (
  1829.                         'value' => preg_replace('/[^0-9.-]+/'''$arrChunks[1]),
  1830.                         'unit' => preg_replace('/[^acehimnprtvwx%]/'''$arrChunks[1])
  1831.                     );
  1832.                     break;
  1833.                 case 'font-family':
  1834.                     $arrSet['font'] = 1;
  1835.                     $arrSet[str_replace('-'''$strKey)] = $arrChunks[1];
  1836.                     break;
  1837.                 case 'font-size':
  1838.                     if (!preg_match('/[0-9]+/'$arrChunks[1]))
  1839.                     {
  1840.                         $arrSet['own'][] = $strDefinition;
  1841.                     }
  1842.                     else
  1843.                     {
  1844.                         $arrSet['font'] = 1;
  1845.                         $arrSet['fontsize'] = array
  1846.                         (
  1847.                             'value' => preg_replace('/[^0-9.-]+/'''$arrChunks[1]),
  1848.                             'unit' => preg_replace('/[^acehimnprtvwx%]/'''$arrChunks[1])
  1849.                         );
  1850.                     }
  1851.                     break;
  1852.                 case 'font-weight':
  1853.                     if ($arrChunks[1] == 'bold' || $arrChunks[1] == 'normal')
  1854.                     {
  1855.                         $arrSet['font'] = 1;
  1856.                         $arrSet['fontstyle'][] = $arrChunks[1];
  1857.                     }
  1858.                     else
  1859.                     {
  1860.                         $arrSet['own'][] = $strDefinition;
  1861.                     }
  1862.                     break;
  1863.                 case 'font-style':
  1864.                     if ($arrChunks[1] == 'italic')
  1865.                     {
  1866.                         $arrSet['font'] = 1;
  1867.                         $arrSet['fontstyle'][] = 'italic';
  1868.                     }
  1869.                     else
  1870.                     {
  1871.                         $arrSet['own'][] = $strDefinition;
  1872.                     }
  1873.                     break;
  1874.                 case 'text-decoration':
  1875.                     $arrSet['font'] = 1;
  1876.                     switch ($arrChunks[1])
  1877.                     {
  1878.                         case 'underline':
  1879.                             $arrSet['fontstyle'][] = 'underline';
  1880.                             break;
  1881.                         case 'none':
  1882.                             $arrSet['fontstyle'][] = 'notUnderlined';
  1883.                             break;
  1884.                         case 'overline':
  1885.                         case 'line-through':
  1886.                             $arrSet['fontstyle'][] = $arrChunks[1];
  1887.                             break;
  1888.                     }
  1889.                     break;
  1890.                 case 'font-variant':
  1891.                     $arrSet['font'] = 1;
  1892.                     if ($arrChunks[1] == 'small-caps')
  1893.                     {
  1894.                         $arrSet['fontstyle'][] = 'small-caps';
  1895.                     }
  1896.                     else
  1897.                     {
  1898.                         $arrSet['own'][] = $strDefinition;
  1899.                     }
  1900.                     break;
  1901.                 case 'color':
  1902.                     if (!preg_match('/^#[a-f0-9]+$/i'$arrChunks[1]))
  1903.                     {
  1904.                         $arrSet['own'][] = $strDefinition;
  1905.                     }
  1906.                     else
  1907.                     {
  1908.                         $arrSet['font'] = 1;
  1909.                         $arrSet['fontcolor'] = str_replace('#'''$arrChunks[1]);
  1910.                     }
  1911.                     break;
  1912.                 case 'line-height':
  1913.                     $arrSet['font'] = 1;
  1914.                     $arrSet['lineheight'] = array
  1915.                     (
  1916.                         'value' => preg_replace('/[^0-9.-]+/'''$arrChunks[1]),
  1917.                         'unit' => preg_replace('/[^acehimnprtvwx%]/'''$arrChunks[1])
  1918.                     );
  1919.                     break;
  1920.                 case 'text-transform':
  1921.                     $arrSet['font'] = 1;
  1922.                     $arrSet['texttransform'] = $arrChunks[1];
  1923.                     break;
  1924.                 case 'text-indent':
  1925.                 case 'letter-spacing':
  1926.                 case 'word-spacing':
  1927.                     $strName str_replace('-'''$strKey);
  1928.                     $arrSet['font'] = 1;
  1929.                     $arrSet[$strName] = array
  1930.                     (
  1931.                         'value' => preg_replace('/[^0-9.-]+/'''$arrChunks[1]),
  1932.                         'unit' => preg_replace('/[^acehimnprtvwx%]/'''$arrChunks[1])
  1933.                     );
  1934.                     break;
  1935.                 case 'list-style-type':
  1936.                     $arrSet['list'] = 1;
  1937.                     $arrSet[str_replace('-'''$strKey)] = $arrChunks[1];
  1938.                     break;
  1939.                 case 'list-style-image':
  1940.                     $arrSet['list'] = 1;
  1941.                     $arrSet['liststyleimage'] = preg_replace('/url\(["\']?([^"\')]+)["\']?\)/i''$1'$arrChunks[1]);
  1942.                     break;
  1943.                 case 'behavior':
  1944.                     $arrSet['own'][] = $strDefinition;
  1945.                     break;
  1946.                 default:
  1947.                     $blnIsOwn true;
  1948.                     // Allow custom definitions
  1949.                     if (isset($GLOBALS['TL_HOOKS']['createDefinition']) && \is_array($GLOBALS['TL_HOOKS']['createDefinition']))
  1950.                     {
  1951.                         foreach ($GLOBALS['TL_HOOKS']['createDefinition'] as $callback)
  1952.                         {
  1953.                             $this->import($callback[0]);
  1954.                             $arrTemp $this->{$callback[0]}->{$callback[1]}($strKey$arrChunks[1], $strDefinition$arrSet);
  1955.                             if ($arrTemp && \is_array($arrTemp))
  1956.                             {
  1957.                                 $blnIsOwn false;
  1958.                                 $arrSet array_merge($arrSet$arrTemp);
  1959.                             }
  1960.                         }
  1961.                     }
  1962.                     // Unknown definition
  1963.                     if ($blnIsOwn)
  1964.                     {
  1965.                         $arrSet['own'][] = $strDefinition;
  1966.                     }
  1967.                     break;
  1968.             }
  1969.         }
  1970.         if (!empty($arrSet['own']))
  1971.         {
  1972.             $arrSet['own'] = implode(";\n"$arrSet['own']) . ';';
  1973.         }
  1974.         $this->Database->prepare("INSERT INTO tl_style %s")->set($arrSet)->execute();
  1975.     }
  1976.     /**
  1977.      * Return an image as data: string
  1978.      *
  1979.      * @param string $strImage
  1980.      * @param array  $arrParent
  1981.      *
  1982.      * @return string|boolean
  1983.      */
  1984.     protected function generateBase64Image($strImage$arrParent)
  1985.     {
  1986.         if (($arrParent['embedImages'] ?? 0) > && file_exists($this->strRootDir '/' $strImage))
  1987.         {
  1988.             $objImage = new File($strImage);
  1989.             $strMime $objImage->extension;
  1990.             // Adjust the mime types
  1991.             if ($strMime == 'jpg')
  1992.             {
  1993.                 $strMime 'jpeg';
  1994.             }
  1995.             elseif ($strMime == 'svg')
  1996.             {
  1997.                 $strMime 'svg+xml';
  1998.             }
  1999.             // Return the data: string
  2000.             if ($objImage->size <= $arrParent['embedImages'])
  2001.             {
  2002.                 return 'data:image/' $strMime ';base64,' base64_encode($objImage->getContent());
  2003.             }
  2004.         }
  2005.         return false;
  2006.     }
  2007. }
  2008. class_alias(StyleSheets::class, 'StyleSheets');