예제 #1
0
 /**
  * Converts the loaded HTML into an HTML-string with inline styles based on the loaded CSS
  *
  * @return string
  * @param  bool [optional] $outputXHTML Should we output valid XHTML?
  */
 public function convert($outputXHTML = false)
 {
     // redefine
     $outputXHTML = (bool) $outputXHTML;
     // validate
     if ($this->html == null) {
         throw new Exception('No HTML provided.');
     }
     // should we use inline style-block
     if ($this->useInlineStylesBlock) {
         // init var
         $matches = array();
         // match the style blocks
         preg_match_all('|<style(.*)>(.*)</style>|isU', $this->html, $matches);
         // any style-blocks found?
         if (!empty($matches[2])) {
             // add
             foreach ($matches[2] as $match) {
                 $this->css .= trim($match) . "\n";
             }
         }
     }
     // process css
     $cssRules = $this->processCSS();
     // create new DOMDocument
     $document = new \DOMDocument('1.0', $this->getEncoding());
     // set error level
     $internalErrors = libxml_use_internal_errors(true);
     // load HTML
     $document->loadHTML($this->html);
     // Restore error level
     libxml_use_internal_errors($internalErrors);
     // create new XPath
     $xPath = new \DOMXPath($document);
     // any rules?
     if (!empty($cssRules)) {
         // loop rules
         foreach ($cssRules as $rule) {
             $selector = new Selector($rule['selector']);
             $query = $selector->toXPath();
             if (is_null($query)) {
                 continue;
             }
             // search elements
             $elements = $xPath->query($query);
             // validate elements
             if ($elements === false) {
                 continue;
             }
             // loop found elements
             foreach ($elements as $element) {
                 // no styles stored?
                 if ($element->attributes->getNamedItem('data-css-to-inline-styles-original-styles') == null) {
                     // init var
                     $originalStyle = '';
                     if ($element->attributes->getNamedItem('style') !== null) {
                         $originalStyle = $element->attributes->getNamedItem('style')->value;
                     }
                     // store original styles
                     $element->setAttribute('data-css-to-inline-styles-original-styles', $originalStyle);
                     // clear the styles
                     $element->setAttribute('style', '');
                 }
                 // init var
                 $properties = array();
                 // get current styles
                 $stylesAttribute = $element->attributes->getNamedItem('style');
                 // any styles defined before?
                 if ($stylesAttribute !== null) {
                     // get value for the styles attribute
                     $definedStyles = (string) $stylesAttribute->value;
                     // split into properties
                     $definedProperties = $this->splitIntoProperties($definedStyles);
                     // loop properties
                     foreach ($definedProperties as $property) {
                         // validate property
                         if ($property == '') {
                             continue;
                         }
                         // split into chunks
                         $chunks = (array) explode(':', trim($property), 2);
                         // validate
                         if (!isset($chunks[1])) {
                             continue;
                         }
                         // loop chunks
                         $properties[$chunks[0]] = trim($chunks[1]);
                     }
                 }
                 // add new properties into the list
                 foreach ($rule['properties'] as $key => $value) {
                     // If one of the rules is already set and is !important, don't apply it,
                     // except if the new rule is also important.
                     if (!isset($properties[$key]) || stristr($properties[$key], '!important') === false || stristr(implode('', $value), '!important') !== false) {
                         $properties[$key] = $value;
                     }
                 }
                 // build string
                 $propertyChunks = array();
                 // build chunks
                 foreach ($properties as $key => $values) {
                     foreach ((array) $values as $value) {
                         $propertyChunks[] = $key . ': ' . $value . ';';
                     }
                 }
                 // build properties string
                 $propertiesString = implode(' ', $propertyChunks);
                 // set attribute
                 if ($propertiesString != '') {
                     $element->setAttribute('style', $propertiesString);
                 }
             }
         }
         // reapply original styles
         // search elements
         $elements = $xPath->query('//*[@data-css-to-inline-styles-original-styles]');
         // loop found elements
         foreach ($elements as $element) {
             // get the original styles
             $originalStyle = $element->attributes->getNamedItem('data-css-to-inline-styles-original-styles')->value;
             if ($originalStyle != '') {
                 $originalProperties = array();
                 $originalStyles = $this->splitIntoProperties($originalStyle);
                 foreach ($originalStyles as $property) {
                     // validate property
                     if ($property == '') {
                         continue;
                     }
                     // split into chunks
                     $chunks = (array) explode(':', trim($property), 2);
                     // validate
                     if (!isset($chunks[1])) {
                         continue;
                     }
                     // loop chunks
                     $originalProperties[$chunks[0]] = trim($chunks[1]);
                 }
                 // get current styles
                 $stylesAttribute = $element->attributes->getNamedItem('style');
                 $properties = array();
                 // any styles defined before?
                 if ($stylesAttribute !== null) {
                     // get value for the styles attribute
                     $definedStyles = (string) $stylesAttribute->value;
                     // split into properties
                     $definedProperties = $this->splitIntoProperties($definedStyles);
                     // loop properties
                     foreach ($definedProperties as $property) {
                         // validate property
                         if ($property == '') {
                             continue;
                         }
                         // split into chunks
                         $chunks = (array) explode(':', trim($property), 2);
                         // validate
                         if (!isset($chunks[1])) {
                             continue;
                         }
                         // loop chunks
                         $properties[$chunks[0]] = trim($chunks[1]);
                     }
                 }
                 // add new properties into the list
                 foreach ($originalProperties as $key => $value) {
                     $properties[$key] = $value;
                 }
                 // build string
                 $propertyChunks = array();
                 // build chunks
                 foreach ($properties as $key => $values) {
                     foreach ((array) $values as $value) {
                         $propertyChunks[] = $key . ': ' . $value . ';';
                     }
                 }
                 // build properties string
                 $propertiesString = implode(' ', $propertyChunks);
                 // set attribute
                 if ($propertiesString != '') {
                     $element->setAttribute('style', $propertiesString);
                 }
             }
             // remove placeholder
             $element->removeAttribute('data-css-to-inline-styles-original-styles');
         }
     }
     // strip original style tags if we need to
     if ($this->stripOriginalStyleTags) {
         $this->stripOriginalStyleTags($xPath);
     }
     // cleanup the HTML if we need to
     if ($this->cleanup) {
         $this->cleanupHTML($xPath);
     }
     // should we output XHTML?
     if ($outputXHTML) {
         // set formating
         $document->formatOutput = true;
         // get the HTML as XML
         $html = $document->saveXML(null, LIBXML_NOEMPTYTAG);
         // remove the XML-header
         $html = ltrim(preg_replace('/<\\?xml (.*)\\?>/', '', $html));
     } else {
         // get the HTML
         $html = $document->saveHTML();
     }
     // return
     return $html;
 }