luminaire /
premailer
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php namespace Luminaire\Premailer\Parser; |
||
| 2 | |||
| 3 | /** |
||
| 4 | * Created by Sublime Text 3 |
||
| 5 | * |
||
| 6 | * @user Kevin Tanjung |
||
| 7 | * @website http://kevintanjung.github.io |
||
| 8 | * @email [email protected] |
||
| 9 | * @date 04/08/2016 |
||
| 10 | * @time 09:09 |
||
| 11 | */ |
||
| 12 | |||
| 13 | use Crossjoin\Css\Reader\CssString as StylesheetReader; |
||
| 14 | use Crossjoin\Css\Format\Rule\AtMedia\MediaQuery; |
||
| 15 | use Crossjoin\Css\Format\Rule\AtMedia\MediaRule; |
||
| 16 | use Crossjoin\Css\Format\Rule\Style\StyleRuleSet; |
||
| 17 | use Crossjoin\Css\Format\Rule\Style\StyleSelector; |
||
| 18 | use Illuminate\Support\Arr; |
||
| 19 | use InvalidArgumentException; |
||
| 20 | |||
| 21 | /** |
||
| 22 | * Retrieve relevant CSS selector from a given CSS rules |
||
| 23 | * |
||
| 24 | * @package \Luminaire\Poseidon\Parser |
||
| 25 | */ |
||
| 26 | class RelevantSelectorParser |
||
| 27 | { |
||
| 28 | |||
| 29 | /** |
||
| 30 | * The pseudo classes that can be set in a style attribute and that are |
||
| 31 | * supported by the Symfony CssSelector (doesn't support CSS4 yet). |
||
| 32 | * |
||
| 33 | * @var array |
||
| 34 | */ |
||
| 35 | protected $allowed_pseudo_classes = [ |
||
| 36 | StyleSelector::PSEUDO_CLASS_FIRST_CHILD, |
||
| 37 | StyleSelector::PSEUDO_CLASS_ROOT, |
||
| 38 | StyleSelector::PSEUDO_CLASS_NTH_CHILD, |
||
| 39 | StyleSelector::PSEUDO_CLASS_NTH_LAST_CHILD, |
||
| 40 | StyleSelector::PSEUDO_CLASS_NTH_OF_TYPE, |
||
| 41 | StyleSelector::PSEUDO_CLASS_NTH_LAST_OF_TYPE, |
||
| 42 | StyleSelector::PSEUDO_CLASS_LAST_CHILD, |
||
| 43 | StyleSelector::PSEUDO_CLASS_FIRST_OF_TYPE, |
||
| 44 | StyleSelector::PSEUDO_CLASS_LAST_OF_TYPE, |
||
| 45 | StyleSelector::PSEUDO_CLASS_ONLY_CHILD, |
||
| 46 | StyleSelector::PSEUDO_CLASS_ONLY_OF_TYPE, |
||
| 47 | StyleSelector::PSEUDO_CLASS_EMPTY, |
||
| 48 | StyleSelector::PSEUDO_CLASS_NOT, |
||
| 49 | ]; |
||
| 50 | |||
| 51 | /** |
||
| 52 | * The stylesheet reader instance |
||
| 53 | * |
||
| 54 | * @var \Crossjoin\Css\Reader\CssString |
||
| 55 | */ |
||
| 56 | protected $reader; |
||
| 57 | |||
| 58 | /** |
||
| 59 | * The charset of the stylesheet |
||
| 60 | * |
||
| 61 | * @var string |
||
| 62 | */ |
||
| 63 | protected $charset; |
||
| 64 | |||
| 65 | /** |
||
| 66 | * Create a new instance of "Relevant Selector Parser" |
||
| 67 | * |
||
| 68 | * @param \Crossjoin\Css\Reader\CssString|string|null $stylesheet |
||
| 69 | * @param string $charset |
||
| 70 | */ |
||
| 71 | public function __construct($stylesheet = null, $charset = 'UTF-8') |
||
| 72 | { |
||
| 73 | $this->charset = $charset; |
||
| 74 | |||
| 75 | if ( ! is_null($stylesheet)) |
||
| 76 | { |
||
| 77 | $this->setStylesheetReader($stylesheet); |
||
| 78 | } |
||
| 79 | } |
||
| 80 | |||
| 81 | /** |
||
| 82 | * Get the relevant selectors |
||
| 83 | * |
||
| 84 | * @return array |
||
| 85 | */ |
||
| 86 | public function extract() |
||
| 87 | { |
||
| 88 | $selectors = []; |
||
| 89 | $rules = $this->reader->getStyleSheet()->getRules(); |
||
| 90 | $relevant = $this->getRelevantStyleRules($rules); |
||
| 91 | |||
| 92 | foreach ($relevant as $rule) |
||
| 93 | { |
||
| 94 | $this->populateSelectors($selectors, $rule); |
||
|
0 ignored issues
–
show
|
|||
| 95 | } |
||
| 96 | |||
| 97 | return $selectors; |
||
| 98 | } |
||
| 99 | |||
| 100 | /** |
||
| 101 | * Store the selectors from the rule to the tank |
||
| 102 | * |
||
| 103 | * @param array &$tank |
||
| 104 | * @param array $rule |
||
| 105 | * @return void |
||
| 106 | */ |
||
| 107 | protected function populateSelectors(array &$tank, $rule) |
||
| 108 | { |
||
| 109 | foreach ($rule->getSelectors() as $selector) |
||
|
0 ignored issues
–
show
|
|||
| 110 | { |
||
| 111 | if ( ! $this->isPseudoClassAllowed($selector)) |
||
| 112 | { |
||
| 113 | continue; |
||
| 114 | } |
||
| 115 | |||
| 116 | $this->prepareSelectorArray( |
||
| 117 | $tank, |
||
| 118 | $selector->getSpecificity(), |
||
| 119 | $selector->getValue() |
||
| 120 | ); |
||
| 121 | |||
| 122 | foreach ($rule->getDeclarations() as $declaration) |
||
|
0 ignored issues
–
show
|
|||
| 123 | { |
||
| 124 | $this->storeDeclaration( |
||
| 125 | $tank, |
||
| 126 | $declaration, |
||
| 127 | $selector->getSpecificity(), |
||
| 128 | $selector->getValue() |
||
| 129 | ); |
||
| 130 | } |
||
| 131 | } |
||
| 132 | } |
||
| 133 | |||
| 134 | /** |
||
| 135 | * Store the declaration in the selector tank |
||
| 136 | * |
||
| 137 | * @param array &$tank |
||
| 138 | * @param \Crossjoin\Css\Format\Rule\Style\StyleDeclaration $declaration |
||
| 139 | * @param string $specifity |
||
| 140 | * @param string $name |
||
| 141 | * @return void |
||
| 142 | */ |
||
| 143 | protected function storeDeclaration(array &$tank, $declaration, $specifity, $name) |
||
| 144 | { |
||
| 145 | $tank[$specifity][$name][] = $declaration; |
||
| 146 | } |
||
| 147 | |||
| 148 | /** |
||
| 149 | * Before we build the dictionary of style declaration, we will need to make |
||
| 150 | * sure, there is an array to be inserted. |
||
| 151 | * |
||
| 152 | * @param array &$selectors |
||
| 153 | * @param string $specifity |
||
| 154 | * @param string $name |
||
| 155 | * @return void |
||
| 156 | */ |
||
| 157 | protected function prepareSelectorArray(array &$selectors, $specifity, $name) |
||
| 158 | { |
||
| 159 | if ( ! isset($selectors[$specifity])) |
||
| 160 | { |
||
| 161 | $selectors[$specifity] = []; |
||
| 162 | } |
||
| 163 | |||
| 164 | if ( ! isset($selectors[$specifity][$name])) |
||
| 165 | { |
||
| 166 | $selectors[$specifity][$name] = []; |
||
| 167 | } |
||
| 168 | } |
||
| 169 | |||
| 170 | /** |
||
| 171 | * Set the stylesheet reader instance |
||
| 172 | * |
||
| 173 | * @param \Crossjoin\Css\Reader\CssString|string $stylesheet |
||
| 174 | * @return $this |
||
| 175 | * |
||
| 176 | * @throws \InvalidArgumentException |
||
| 177 | */ |
||
| 178 | public function setStylesheetReader($stylesheet) |
||
| 179 | { |
||
| 180 | if (is_string($stylesheet)) |
||
| 181 | { |
||
| 182 | $stylesheet = new StylesheetReader($stylesheet); |
||
| 183 | } |
||
| 184 | |||
| 185 | if ( ! $stylesheet instanceof StylesheetReader) |
||
| 186 | { |
||
| 187 | throw new InvalidArgumentException('The argument 0 of the [setStylesheetReader] method expects to be a string of CSS or a [Crossjoin\Css\Reader\CssString]'); |
||
| 188 | } |
||
| 189 | |||
| 190 | $this->reader = $stylesheet; |
||
| 191 | $this->reader->setEnvironmentEncoding($this->getCharset()); |
||
| 192 | |||
| 193 | return $this; |
||
| 194 | } |
||
| 195 | |||
| 196 | /** |
||
| 197 | * Get the stylesheet reader instance |
||
| 198 | * |
||
| 199 | * @return \Crossjoin\Css\Reader\CssString|null |
||
| 200 | */ |
||
| 201 | public function getStylesheetReader() |
||
| 202 | { |
||
| 203 | return $this->reader; |
||
| 204 | } |
||
| 205 | |||
| 206 | /** |
||
| 207 | * Set the charset of the stylesheet |
||
| 208 | * |
||
| 209 | * @param string $charset |
||
| 210 | * @return $this |
||
| 211 | */ |
||
| 212 | public function setCharset($charset) |
||
| 213 | { |
||
| 214 | $this->charset = $charset; |
||
| 215 | |||
| 216 | return $this; |
||
| 217 | } |
||
| 218 | |||
| 219 | /** |
||
| 220 | * Get the charset of the stylesheet |
||
| 221 | * |
||
| 222 | * @return string |
||
| 223 | */ |
||
| 224 | public function getCharset() |
||
| 225 | { |
||
| 226 | return $this->charset; |
||
| 227 | } |
||
| 228 | |||
| 229 | /** |
||
| 230 | * Check if a Selector has a valid Pseudo Class |
||
| 231 | * |
||
| 232 | * @param \Crossjoin\Css\Format\Rule\Style\StyleSelector $selector |
||
| 233 | * @return bool |
||
| 234 | */ |
||
| 235 | public function isPseudoClassAllowed(StyleSelector $selector) |
||
| 236 | { |
||
| 237 | foreach ($selector->getPseudoClasses() as $pseudo_class) |
||
| 238 | { |
||
| 239 | if ( ! in_array($pseudo_class, $this->allowed_pseudo_classes)) |
||
| 240 | { |
||
| 241 | return false; |
||
| 242 | } |
||
| 243 | } |
||
| 244 | |||
| 245 | return true; |
||
| 246 | } |
||
| 247 | |||
| 248 | /** |
||
| 249 | * Gets all generally relevant style rules |
||
| 250 | * |
||
| 251 | * @param \Crossjoin\Css\Format\Rule\RuleAbstract[] $rules |
||
| 252 | * @return \Crossjoin\Css\Format\Rule\Style\StyleRuleSet[] |
||
| 253 | */ |
||
| 254 | protected function getRelevantStyleRules(array $rules) |
||
| 255 | { |
||
| 256 | $relevants = []; |
||
| 257 | |||
| 258 | foreach ($rules as $rule) |
||
| 259 | { |
||
| 260 | if ($rule instanceof StyleRuleSet) |
||
| 261 | { |
||
| 262 | $relevants[] = $rule; |
||
| 263 | } |
||
| 264 | |||
| 265 | if ($rule instanceof MediaRule) |
||
| 266 | { |
||
| 267 | $this->getRelevantMediaRule($rule, $relevants); |
||
| 268 | } |
||
| 269 | } |
||
| 270 | |||
| 271 | return $relevants; |
||
| 272 | } |
||
| 273 | |||
| 274 | /** |
||
| 275 | * Gets the relevant style rules from a media rule |
||
| 276 | * |
||
| 277 | * @param \Crossjoin\Css\Format\Rule\AtMedia\MediaRule $rule |
||
| 278 | * @param array &$collection |
||
| 279 | * @return void |
||
| 280 | */ |
||
| 281 | protected function getRelevantMediaRule(MediaRule $rule, &$collection) |
||
| 282 | { |
||
| 283 | foreach ($rule->getQueries() as $media_query) |
||
| 284 | { |
||
| 285 | if ( ! $this->isAllowedMediaRule($media_query)) |
||
| 286 | { |
||
| 287 | continue; |
||
| 288 | } |
||
| 289 | |||
| 290 | foreach ($this->getRelevantStyleRules($rule->getRules()) as $style_rule) |
||
| 291 | { |
||
| 292 | $collection[] = $style_rule; |
||
| 293 | } |
||
| 294 | |||
| 295 | break; |
||
| 296 | } |
||
| 297 | } |
||
| 298 | |||
| 299 | /** |
||
| 300 | * Check if the media rule should be included |
||
| 301 | * |
||
| 302 | * @param \Crossjoin\Css\Format\Rule\AtMedia\MediaQuery $media_query |
||
| 303 | * @return bool |
||
| 304 | */ |
||
| 305 | protected function isAllowedMediaRule(MediaQuery $media_query) |
||
| 306 | { |
||
| 307 | $type = $media_query->getType(); |
||
| 308 | $condition = count($media_query->getConditions()); |
||
| 309 | |||
| 310 | return ($type === MediaQuery::TYPE_ALL || $type === MediaQuery::TYPE_SCREEN) && $condition === 0; |
||
| 311 | } |
||
| 312 | |||
| 313 | } |
||
| 314 |
It seems like the type of the argument is not accepted by the function/method which you are calling.
In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.
We suggest to add an explicit type cast like in the following example: