1function ReadCSS($html) { 2 preg_match_all('/<style[^>]*media=["\']([^"\'>]*)["\'].*?<\/style>/is',$html,$m); 3 for($i=0; $i<count($m[0]); $i++) { 4 if ($this->mpdf->CSSselectMedia && !preg_match('/('.trim($this->mpdf->CSSselectMedia).'|all)/i',$m[1][$i])) { 5 $html = str_replace($m[0][$i],'',$html); 6 } 7 } 8 preg_match_all('/<link[^>]*media=["\']([^"\'>]*)["\'].*?>/is',$html,$m); 9 for($i=0; $i<count($m[0]); $i++) { 10 if ($this->mpdf->CSSselectMedia && !preg_match('/('.trim($this->mpdf->CSSselectMedia).'|all)/i',$m[1][$i])) { 11 $html = str_replace($m[0][$i],'',$html); 12 } 13 } 14 15 // mPDF 5.5.02 16 // Remove Comment tags <!-- ... --> inside CSS as <style> in HTML document 17 // Remove Comment tags /* ... */ inside CSS as <style> in HTML document 18 // But first, we replace upper and mixed case closing style tag with lower 19 // case so we can use str_replace later. 20 preg_replace('/<\/style>/i', '</style>', $html); 21 preg_match_all('/<style.*?>(.*?)<\/style>/si',$html,$m); 22 if (count($m[1])) { 23 for($i=0;$i<count($m[1]);$i++) { 24 // Remove comment tags 25 $sub = preg_replace('/(<\!\-\-|\-\->)/s',' ',$m[1][$i]); 26 $sub = '>'.preg_replace('|/\*.*?\*/|s',' ',$sub).'</style>'; 27 $html = str_replace('>'.$m[1][$i].'</style>', $sub, $html); 28 } 29 } 30 31 32 $html = preg_replace('/<!--mpdf/i','',$html); 33 $html = preg_replace('/mpdf-->/i','',$html); 34 $html = preg_replace('/<\!\-\-.*?\-\->/s',' ',$html); 35 36 $match = 0; // no match for instance 37 $regexp = ''; // This helps debugging: showing what is the REAL string being processed 38 $CSSext = array(); 39 40 //CSS inside external files 41 $regexp = '/<link[^>]*rel=["\']stylesheet["\'][^>]*href=["\']([^>"\']*)["\'].*?>/si'; 42 $x = preg_match_all($regexp,$html,$cxt); 43 if ($x) { 44 $match += $x; 45 $CSSext = $cxt[1]; 46 } 47 48 $regexp = '/<link[^>]*href=["\']([^>"\']*)["\'][^>]*?rel=["\']stylesheet["\'].*?>/si'; 49 $x = preg_match_all($regexp,$html,$cxt); 50 if ($x) { 51 $match += $x; 52 $CSSext = array_merge($CSSext,$cxt[1]); 53 } 54 55 // look for @import stylesheets 56 //$regexp = '/@import url\([\'\"]{0,1}([^\)]*?\.css)[\'\"]{0,1}\)/si'; 57 $regexp = '/@import url\([\'\"]{0,1}([^\)]*?\.css(\?\S+)?)[\'\"]{0,1}\)/si'; 58 $x = preg_match_all($regexp,$html,$cxt); 59 if ($x) { 60 $match += $x; 61 $CSSext = array_merge($CSSext,$cxt[1]); 62 } 63 64 // look for @import without the url() 65 //$regexp = '/@import [\'\"]{0,1}([^;]*?\.css)[\'\"]{0,1}/si'; 66 $regexp = '/@import [\'\"]{0,1}([^;]*?\.css(\?\S+)?)[\'\"]{0,1}/si'; 67 $x = preg_match_all($regexp,$html,$cxt); 68 if ($x) { 69 $match += $x; 70 $CSSext = array_merge($CSSext,$cxt[1]); 71 } 72 73 $ind = 0; 74 $CSSstr = ''; 75 76 if (!is_array($this->cascadeCSS)) $this->cascadeCSS = array(); 77 78 while($match){ 79 $path = $CSSext[$ind]; 80 81 $path = htmlspecialchars_decode($path); // mPDF 6 82 83 $this->mpdf->GetFullPath($path); 84 $CSSextblock = $this->mpdf->_get_file($path); 85 if ($CSSextblock) { 86 // look for embedded @import stylesheets in other stylesheets 87 // and fix url paths (including background-images) relative to stylesheet 88 //$regexpem = '/@import url\([\'\"]{0,1}(.*?\.css)[\'\"]{0,1}\)/si'; 89 $regexpem = '/@import url\([\'\"]{0,1}(.*?\.css(\?\S+)?)[\'\"]{0,1}\)/si'; 90 $xem = preg_match_all($regexpem,$CSSextblock,$cxtem); 91 $cssBasePath = preg_replace('/\/[^\/]*$/','',$path) . '/'; 92 if ($xem) { 93 foreach($cxtem[1] AS $cxtembedded) { 94 // path is relative to original stlyesheet!! 95 $this->mpdf->GetFullPath($cxtembedded, $cssBasePath ); 96 $match++; 97 $CSSext[] = $cxtembedded; 98 } 99 } 100 $regexpem = '/(background[^;]*url\s*\(\s*[\'\"]{0,1})([^\)\'\"]*)([\'\"]{0,1}\s*\))/si'; 101 $xem = preg_match_all($regexpem,$CSSextblock,$cxtem); 102 if ($xem) { 103 for ($i=0;$i<count($cxtem[0]);$i++) { 104 // path is relative to original stlyesheet!! 105 $embedded = $cxtem[2][$i]; 106 if (!preg_match('/^data:image/i', $embedded)) { // mPDF 5.5.13 107 $this->mpdf->GetFullPath($embedded, $cssBasePath ); 108 $CSSextblock = str_replace($cxtem[0][$i], ($cxtem[1][$i].$embedded.$cxtem[3][$i]), $CSSextblock); 109 } 110 } 111 } 112 $CSSstr .= ' '.$CSSextblock; 113 } 114 $match--; 115 $ind++; 116 } //end of match 117 118 $match = 0; // reset value, if needed 119 // CSS as <style> in HTML document 120 $regexp = '/<style.*?>(.*?)<\/style>/si'; 121 $match = preg_match_all($regexp,$html,$CSSblock); 122 if ($match) { 123 $tmpCSSstr = implode(' ',$CSSblock[1]); 124 $regexpem = '/(background[^;]*url\s*\(\s*[\'\"]{0,1})([^\)\'\"]*)([\'\"]{0,1}\s*\))/si'; 125 $xem = preg_match_all($regexpem,$tmpCSSstr ,$cxtem); 126 if ($xem) { 127 for ($i=0;$i<count($cxtem[0]);$i++) { 128 $embedded = $cxtem[2][$i]; 129 if (!preg_match('/^data:image/i', $embedded)) { // mPDF 5.5.13 130 $this->mpdf->GetFullPath($embedded); 131 $tmpCSSstr = str_replace($cxtem[0][$i], ($cxtem[1][$i].$embedded.$cxtem[3][$i]), $tmpCSSstr ); 132 } 133 } 134 } 135 $CSSstr .= ' '.$tmpCSSstr; 136 } 137 // Remove comments 138 $CSSstr = preg_replace('|/\*.*?\*/|s',' ',$CSSstr); 139 $CSSstr = preg_replace('/[\s\n\r\t\f]/s',' ',$CSSstr); 140 141 if (preg_match('/@media/',$CSSstr)) { 142 preg_match_all('/@media(.*?)\{(([^\{\}]*\{[^\{\}]*\})+)\s*\}/is',$CSSstr,$m); 143 for($i=0; $i<count($m[0]); $i++) { 144 if ($this->mpdf->CSSselectMedia && !preg_match('/('.trim($this->mpdf->CSSselectMedia).'|all)/is',$m[1][$i])) { 145 $CSSstr = str_replace($m[0][$i], '', $CSSstr); 146 } 147 else { 148 $CSSstr = str_replace($m[0][$i],' '.$m[2][$i].' ',$CSSstr); 149 } 150 } 151 } 152 153 // mPDF 5.5.13 154 // Replace any background: url(data:image... with temporary image file reference 155 preg_match_all("/(url\(data:image\/(jpeg|gif|png);base64,(.*?)\))/si", $CSSstr, $idata); // mPDF 5.7.2 156 if (count($idata[0])) { 157 for($i=0;$i<count($idata[0]);$i++) { 158 $file = _MPDF_TEMP_PATH.'_tempCSSidata'.RAND(1,10000).'_'.$i.'.'.$idata[2][$i]; 159 //Save to local file 160 file_put_contents($file, base64_decode($idata[3][$i])); 161 // $this->mpdf->GetFullPath($file); // ? is this needed - NO mPDF 5.6.03 162 $CSSstr = str_replace($idata[0][$i], 'url("'.$file.'")', $CSSstr); // mPDF 5.5.17 163 } 164 } 165 166 $CSSstr = preg_replace('/(<\!\-\-|\-\->)/s',' ',$CSSstr); 167 168 // mPDF 5.7.4 URLs 169 // Characters "(" ")" and ";" in url() e.g. background-image, cause problems parsing the CSS string 170 // URLencode ( and ), but change ";" to a code which can be converted back after parsing (so as not to confuse ; 171 // with a segment delimiter in the URI) 172 $tempmarker = '%ZZ'; 173 if (strpos($CSSstr,'url(')!==false) { 174 preg_match_all( '/url\(\"(.*?)\"\)/', $CSSstr, $m); 175 for($i = 0; $i < count($m[1]) ; $i++) { 176 $tmp = str_replace(array('(',')',';'),array('%28','%29',$tempmarker),$m[1][$i]); 177 $CSSstr = preg_replace('/'.preg_quote($m[0][$i],'/').'/', 'url(\''.$tmp.'\')', $CSSstr); 178 } 179 preg_match_all( '/url\(\'(.*?)\'\)/', $CSSstr, $m); 180 for($i = 0; $i < count($m[1]) ; $i++) { 181 $tmp = str_replace(array('(',')',';'),array('%28','%29',$tempmarker),$m[1][$i]); 182 $CSSstr = preg_replace('/'.preg_quote($m[0][$i],'/').'/', 'url(\''.$tmp.'\')', $CSSstr); 183 } 184 preg_match_all( '/url\(([^\'\"].*?[^\'\"])\)/', $CSSstr, $m); 185 for($i = 0; $i < count($m[1]) ; $i++) { 186 $tmp = str_replace(array('(',')',';'),array('%28','%29',$tempmarker),$m[1][$i]); 187 $CSSstr = preg_replace('/'.preg_quote($m[0][$i],'/').'/', 'url(\''.$tmp.'\')', $CSSstr); 188 } 189 } 190 191 192 193 if ($CSSstr ) { 194 $classproperties = array(); // mPDF 6 195 preg_match_all('/(.*?)\{(.*?)\}/',$CSSstr,$styles); 196 for($i=0; $i < count($styles[1]) ; $i++) { 197 // SET array e.g. $classproperties['COLOR'] = '#ffffff'; 198 $stylestr= trim($styles[2][$i]); 199 $stylearr = explode(';',$stylestr); 200 foreach($stylearr AS $sta) { 201 if (trim($sta)) { 202 // Changed to allow style="background: url('http://www.bpm1.com/bg.jpg')" 203 $tmp = explode(':',$sta,2); 204 $property = $tmp[0]; 205 if (isset($tmp[1])) { $value = $tmp[1]; } 206 else { $value = ''; } 207 $value = str_replace($tempmarker,';',$value); // mPDF 5.7.4 URLs 208 $property = trim($property); 209 $value = preg_replace('/\s*!important/i','',$value); 210 $value = trim($value); 211 if ($property && ($value || $value==='0')) { 212 // Ignores -webkit-gradient so doesn't override -moz- 213 if ((strtoupper($property)=='BACKGROUND-IMAGE' || strtoupper($property)=='BACKGROUND') && preg_match('/-webkit-gradient/i',$value)) { 214 continue; 215 } 216 $classproperties[strtoupper($property)] = $value; 217 } 218 } 219 } 220 $classproperties = $this->fixCSS($classproperties); 221 $tagstr = strtoupper(trim($styles[1][$i])); 222 $tagarr = explode(',',$tagstr); 223 $pageselectors = false; // used to turn on $this->mpdf->mirrorMargins 224 foreach($tagarr AS $tg) { 225 // mPDF 5.7.4 226 if (preg_match('/NTH-CHILD\((\s*(([\-+]?\d*)N(\s*[\-+]\s*\d+)?|[\-+]?\d+|ODD|EVEN)\s*)\)/',$tg,$m) ) { 227 $tg = preg_replace('/NTH-CHILD\(.*\)/', 'NTH-CHILD('.str_replace(' ','',$m[1]).')', $tg); 228 } 229 $tags = preg_split('/\s+/',trim($tg)); 230 $level = count($tags); 231 $t = ''; 232 $t2 = ''; 233 $t3 = ''; 234 if (trim($tags[0])=='@PAGE') { 235 if (isset($tags[0])) { $t = trim($tags[0]); } 236 if (isset($tags[1])) { $t2 = trim($tags[1]); } 237 if (isset($tags[2])) { $t3 = trim($tags[2]); } 238 $tag = ''; 239 if ($level==1) { $tag = $t; } 240 else if ($level==2 && preg_match('/^[:](.*)$/',$t2,$m)) { 241 $tag = $t.'>>PSEUDO>>'.$m[1]; 242 if ($m[1]=='LEFT' || $m[1]=='RIGHT') { $pageselectors = true; } // used to turn on $this->mpdf->mirrorMargins 243 } 244 else if ($level==2) { $tag = $t.'>>NAMED>>'.$t2; } 245 else if ($level==3 && preg_match('/^[:](.*)$/',$t3,$m)) { 246 $tag = $t.'>>NAMED>>'.$t2.'>>PSEUDO>>'.$m[1]; 247 if ($m[1]=='LEFT' || $m[1]=='RIGHT') { $pageselectors = true; } // used to turn on $this->mpdf->mirrorMargins 248 } 249 if (isset($this->CSS[$tag]) && $tag) { $this->CSS[$tag] = $this->array_merge_recursive_unique($this->CSS[$tag], $classproperties); } 250 else if ($tag) { $this->CSS[$tag] = $classproperties; } 251 } 252 253 else if ($level == 1) { // e.g. p or .class or #id or p.class or p#id 254 if (isset($tags[0])) { $t = trim($tags[0]); } 255 if ($t) { 256 $tag = ''; 257 if (preg_match('/^[.](.*)$/',$t,$m)) { $tag = 'CLASS>>'.$m[1]; } 258 else if (preg_match('/^[#](.*)$/',$t,$m)) { $tag = 'ID>>'.$m[1]; } 259 else if (preg_match('/^\[LANG=[\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\]$/',$t,$m)) { $tag = 'LANG>>'.strtolower($m[1]); } // mPDF 6 Special case for lang as attribute selector 260 else if (preg_match('/^:LANG\([\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\)$/',$t,$m)) { $tag = 'LANG>>'.strtolower($m[1]); } // mPDF 6 Special case for lang as attribute selector 261 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')[.](.*)$/',$t,$m)) { $tag = $m[1].'>>CLASS>>'.$m[2]; } 262 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')\s*:NTH-CHILD\((.*)\)$/',$t,$m)) { $tag = $m[1].'>>SELECTORNTHCHILD>>'.$m[2]; } 263 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')[#](.*)$/',$t,$m)) { $tag = $m[1].'>>ID>>'.$m[2]; } 264 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')\[LANG=[\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\]$/',$t,$m)) { $tag = $m[1].'>>LANG>>'.strtolower($m[2]); } // mPDF 6 Special case for lang as attribute selector 265 else if (preg_match('/^('.$this->mpdf->allowedCSStags.'):LANG\([\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\)$/',$t,$m)) { $tag = $m[1].'>>LANG>>'.strtolower($m[2]); } // mPDF 6 Special case for lang as attribute selector 266 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')$/',$t)) { $tag= $t; } 267 if (isset($this->CSS[$tag]) && $tag) { $this->CSS[$tag] = $this->array_merge_recursive_unique($this->CSS[$tag], $classproperties); } 268 else if ($tag) { $this->CSS[$tag] = $classproperties; } 269 } 270 } 271 else { 272 $tmp = array(); 273 for($n=0;$n<$level;$n++) { 274 if (isset($tags[$n])) { $t = trim($tags[$n]); } 275 else { $t = ''; } 276 if ($t) { 277 $tag = ''; 278 if (preg_match('/^[.](.*)$/',$t,$m)) { $tag = 'CLASS>>'.$m[1]; } 279 else if (preg_match('/^[#](.*)$/',$t,$m)) { $tag = 'ID>>'.$m[1]; } 280 else if (preg_match('/^\[LANG=[\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\]$/',$t,$m)) { $tag = 'LANG>>'.strtolower($m[1]); } // mPDF 6 Special case for lang as attribute selector 281 else if (preg_match('/^:LANG\([\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\)$/',$t,$m)) { $tag = 'LANG>>'.strtolower($m[1]); } // mPDF 6 Special case for lang as attribute selector 282 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')[.](.*)$/',$t,$m)) { $tag = $m[1].'>>CLASS>>'.$m[2]; } 283 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')\s*:NTH-CHILD\((.*)\)$/',$t,$m)) { $tag = $m[1].'>>SELECTORNTHCHILD>>'.$m[2]; } 284 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')[#](.*)$/',$t,$m)) { $tag = $m[1].'>>ID>>'.$m[2]; } 285 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')\[LANG=[\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\]$/',$t,$m)) { $tag = $m[1].'>>LANG>>'.strtolower($m[2]); } // mPDF 6 Special case for lang as attribute selector 286 else if (preg_match('/^('.$this->mpdf->allowedCSStags.'):LANG\([\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\)$/',$t,$m)) { $tag = $m[1].'>>LANG>>'.strtolower($m[2]); } // mPDF 6 Special case for lang as attribute selector 287 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')$/',$t)) { $tag= $t; } 288 289 if ($tag) $tmp[] = $tag; 290 else { break; } 291 } 292 } 293 294 if ($tag) { 295 $x = &$this->cascadeCSS; 296 foreach($tmp AS $tp) { $x = &$x[$tp]; } 297 $x = $this->array_merge_recursive_unique($x, $classproperties); 298 $x['depth'] = $level; 299 } 300 } 301 } 302 if ($pageselectors) { $this->mpdf->mirrorMargins = true; } 303 $properties = array(); 304 $values = array(); 305 $classproperties = array(); 306 } 307 } // end of if 308 //Remove CSS (tags and content), if any 309 $regexp = '/<style.*?>(.*?)<\/style>/si'; // it can be <style> or <style type="txt/css"> 310 $html = preg_replace($regexp,'',$html); 311//print_r($this->CSS); exit; 312//print_r($this->cascadeCSS); exit; 313 return $html; 314} 315