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 $this->mpdf->GetFullPath($path); 81 $CSSextblock = $this->mpdf->_get_file($path); 82 if ($CSSextblock) { 83 // look for embedded @import stylesheets in other stylesheets 84 // and fix url paths (including background-images) relative to stylesheet 85 //$regexpem = '/@import url\([\'\"]{0,1}(.*?\.css)[\'\"]{0,1}\)/si'; 86 $regexpem = '/@import url\([\'\"]{0,1}(.*?\.css(\?\S+)?)[\'\"]{0,1}\)/si'; 87 $xem = preg_match_all($regexpem,$CSSextblock,$cxtem); 88 $cssBasePath = preg_replace('/\/[^\/]*$/','',$path) . '/'; 89 if ($xem) { 90 foreach($cxtem[1] AS $cxtembedded) { 91 // path is relative to original stlyesheet!! 92 $this->mpdf->GetFullPath($cxtembedded, $cssBasePath ); 93 $match++; 94 $CSSext[] = $cxtembedded; 95 } 96 } 97 $regexpem = '/(background[^;]*url\s*\(\s*[\'\"]{0,1})([^\)\'\"]*)([\'\"]{0,1}\s*\))/si'; 98 $xem = preg_match_all($regexpem,$CSSextblock,$cxtem); 99 if ($xem) { 100 for ($i=0;$i<count($cxtem[0]);$i++) { 101 // path is relative to original stlyesheet!! 102 $embedded = $cxtem[2][$i]; 103 if (!preg_match('/^data:image/i', $embedded)) { // mPDF 5.5.13 104 $this->mpdf->GetFullPath($embedded, $cssBasePath ); 105 $CSSextblock = str_replace($cxtem[0][$i], ($cxtem[1][$i].$embedded.$cxtem[3][$i]), $CSSextblock); 106 } 107 } 108 } 109 $CSSstr .= ' '.$CSSextblock; 110 } 111 $match--; 112 $ind++; 113 } //end of match 114 115 $match = 0; // reset value, if needed 116 // CSS as <style> in HTML document 117 $regexp = '/<style.*?>(.*?)<\/style>/si'; 118 $match = preg_match_all($regexp,$html,$CSSblock); 119 if ($match) { 120 $tmpCSSstr = implode(' ',$CSSblock[1]); 121 $regexpem = '/(background[^;]*url\s*\(\s*[\'\"]{0,1})([^\)\'\"]*)([\'\"]{0,1}\s*\))/si'; 122 $xem = preg_match_all($regexpem,$tmpCSSstr ,$cxtem); 123 if ($xem) { 124 for ($i=0;$i<count($cxtem[0]);$i++) { 125 $embedded = $cxtem[2][$i]; 126 if (!preg_match('/^data:image/i', $embedded)) { // mPDF 5.5.13 127 $this->mpdf->GetFullPath($embedded); 128 $tmpCSSstr = str_replace($cxtem[0][$i], ($cxtem[1][$i].$embedded.$cxtem[3][$i]), $tmpCSSstr ); 129 } 130 } 131 } 132 $CSSstr .= ' '.$tmpCSSstr; 133 } 134 // Remove comments 135 $CSSstr = preg_replace('|/\*.*?\*/|s',' ',$CSSstr); 136 $CSSstr = preg_replace('/[\s\n\r\t\f]/s',' ',$CSSstr); 137 138 if (preg_match('/@media/',$CSSstr)) { 139 preg_match_all('/@media(.*?)\{(([^\{\}]*\{[^\{\}]*\})+)\s*\}/is',$CSSstr,$m); 140 for($i=0; $i<count($m[0]); $i++) { 141 if ($this->mpdf->CSSselectMedia && !preg_match('/('.trim($this->mpdf->CSSselectMedia).'|all)/is',$m[1][$i])) { 142 $CSSstr = str_replace($m[0][$i], '', $CSSstr); 143 } 144 else { 145 $CSSstr = str_replace($m[0][$i],' '.$m[2][$i].' ',$CSSstr); 146 } 147 } 148 } 149 150 // mPDF 5.5.13 151 // Replace any background: url(data:image... with temporary image file reference 152 preg_match_all("/(url\(data:image\/(jpeg|gif|png);base64,(.*)\))/si", $CSSstr, $idata); 153 if (count($idata[0])) { 154 for($i=0;$i<count($idata[0]);$i++) { 155 $file = _MPDF_TEMP_PATH.'_tempCSSidata'.RAND(1,10000).'_'.$i.'.'.$idata[2][$i]; 156 //Save to local file 157 file_put_contents($file, base64_decode($idata[3][$i])); 158 // $this->mpdf->GetFullPath($file); // ? is this needed - NO mPDF 5.6.03 159 $CSSstr = str_replace($idata[0][$i], 'url("'.$file.'")', $CSSstr); // mPDF 5.5.17 160 } 161 } 162 163 $CSSstr = preg_replace('/(<\!\-\-|\-\->)/s',' ',$CSSstr); 164 165 // mPDF 5.7.4 URLs 166 // Characters "(" ")" and ";" in url() e.g. background-image, cause problems parsing the CSS string 167 // URLencode ( and ), but change ";" to a code which can be converted back after parsing (so as not to confuse ; 168 // with a segment delimiter in the URI) 169 $tempmarker = '%ZZ'; 170 if (strpos($CSSstr,'url(')!==false) { 171 preg_match_all( '/url\(\"(.*?)\"\)/', $CSSstr, $m); 172 for($i = 0; $i < count($m[1]) ; $i++) { 173 $tmp = str_replace(array('(',')',';'),array('%28','%29',$tempmarker),$m[1][$i]); 174 $CSSstr = preg_replace('/'.preg_quote($m[0][$i],'/').'/', 'url(\''.$tmp.'\')', $CSSstr); 175 } 176 preg_match_all( '/url\(\'(.*?)\'\)/', $CSSstr, $m); 177 for($i = 0; $i < count($m[1]) ; $i++) { 178 $tmp = str_replace(array('(',')',';'),array('%28','%29',$tempmarker),$m[1][$i]); 179 $CSSstr = preg_replace('/'.preg_quote($m[0][$i],'/').'/', 'url(\''.$tmp.'\')', $CSSstr); 180 } 181 preg_match_all( '/url\(([^\'\"].*?[^\'\"])\)/', $CSSstr, $m); 182 for($i = 0; $i < count($m[1]) ; $i++) { 183 $tmp = str_replace(array('(',')',';'),array('%28','%29',$tempmarker),$m[1][$i]); 184 $CSSstr = preg_replace('/'.preg_quote($m[0][$i],'/').'/', 'url(\''.$tmp.'\')', $CSSstr); 185 } 186 } 187 188 189 190 if ($CSSstr ) { 191 $classproperties = array(); // mPDF 6 192 preg_match_all('/(.*?)\{(.*?)\}/',$CSSstr,$styles); 193 for($i=0; $i < count($styles[1]) ; $i++) { 194 // SET array e.g. $classproperties['COLOR'] = '#ffffff'; 195 $stylestr= trim($styles[2][$i]); 196 $stylearr = explode(';',$stylestr); 197 foreach($stylearr AS $sta) { 198 if (trim($sta)) { 199 // Changed to allow style="background: url('http://www.bpm1.com/bg.jpg')" 200 $tmp = explode(':',$sta,2); 201 $property = $tmp[0]; 202 if (isset($tmp[1])) { $value = $tmp[1]; } 203 else { $value = ''; } 204 $value = str_replace($tempmarker,';',$value); // mPDF 5.7.4 URLs 205 $property = trim($property); 206 $value = preg_replace('/\s*!important/i','',$value); 207 $value = trim($value); 208 if ($property && ($value || $value==='0')) { 209 // Ignores -webkit-gradient so doesn't override -moz- 210 if ((strtoupper($property)=='BACKGROUND-IMAGE' || strtoupper($property)=='BACKGROUND') && preg_match('/-webkit-gradient/i',$value)) { 211 continue; 212 } 213 $classproperties[strtoupper($property)] = $value; 214 } 215 } 216 } 217 $classproperties = $this->fixCSS($classproperties); 218 $tagstr = strtoupper(trim($styles[1][$i])); 219 $tagarr = explode(',',$tagstr); 220 $pageselectors = false; // used to turn on $this->mpdf->mirrorMargins 221 foreach($tagarr AS $tg) { 222 // mPDF 5.7.4 223 if (preg_match('/NTH-CHILD\((\s*(([\-+]?\d*)N(\s*[\-+]\s*\d+)?|[\-+]?\d+|ODD|EVEN)\s*)\)/',$tg,$m) ) { 224 $tg = preg_replace('/NTH-CHILD\(.*\)/', 'NTH-CHILD('.str_replace(' ','',$m[1]).')', $tg); 225 } 226 $tags = preg_split('/\s+/',trim($tg)); 227 $level = count($tags); 228 $t = ''; 229 $t2 = ''; 230 $t3 = ''; 231 if (trim($tags[0])=='@PAGE') { 232 if (isset($tags[0])) { $t = trim($tags[0]); } 233 if (isset($tags[1])) { $t2 = trim($tags[1]); } 234 if (isset($tags[2])) { $t3 = trim($tags[2]); } 235 $tag = ''; 236 if ($level==1) { $tag = $t; } 237 else if ($level==2 && preg_match('/^[:](.*)$/',$t2,$m)) { 238 $tag = $t.'>>PSEUDO>>'.$m[1]; 239 if ($m[1]=='LEFT' || $m[1]=='RIGHT') { $pageselectors = true; } // used to turn on $this->mpdf->mirrorMargins 240 } 241 else if ($level==2) { $tag = $t.'>>NAMED>>'.$t2; } 242 else if ($level==3 && preg_match('/^[:](.*)$/',$t3,$m)) { 243 $tag = $t.'>>NAMED>>'.$t2.'>>PSEUDO>>'.$m[1]; 244 if ($m[1]=='LEFT' || $m[1]=='RIGHT') { $pageselectors = true; } // used to turn on $this->mpdf->mirrorMargins 245 } 246 if (isset($this->CSS[$tag]) && $tag) { $this->CSS[$tag] = $this->array_merge_recursive_unique($this->CSS[$tag], $classproperties); } 247 else if ($tag) { $this->CSS[$tag] = $classproperties; } 248 } 249 else if ($level == 1) { // e.g. p or .class or #id or p.class or p#id 250 if (isset($tags[0])) { $t = trim($tags[0]); } 251 if ($t) { 252 $tag = ''; 253 if (preg_match('/^[.](.*)$/',$t,$m)) { $tag = 'CLASS>>'.$m[1]; } 254 else if (preg_match('/^[#](.*)$/',$t,$m)) { $tag = 'ID>>'.$m[1]; } 255 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 256 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 257 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')[.](.*)$/',$t,$m)) { $tag = $m[1].'>>CLASS>>'.$m[2]; } 258 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')\s*:NTH-CHILD\((.*)\)$/',$t,$m)) { $tag = $m[1].'>>SELECTORNTHCHILD>>'.$m[2]; } 259 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')[#](.*)$/',$t,$m)) { $tag = $m[1].'>>ID>>'.$m[2]; } 260 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 261 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 262 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')$/',$t)) { $tag= $t; } 263 if (isset($this->CSS[$tag]) && $tag) { $this->CSS[$tag] = $this->array_merge_recursive_unique($this->CSS[$tag], $classproperties); } 264 else if ($tag) { $this->CSS[$tag] = $classproperties; } 265 } 266 } 267 else { 268 $tmp = array(); 269 for($n=0;$n<$level;$n++) { 270 if (isset($tags[$n])) { $t = trim($tags[$n]); } 271 else { $t = ''; } 272 if ($t) { 273 $tag = ''; 274 if (preg_match('/^[.](.*)$/',$t,$m)) { $tag = 'CLASS>>'.$m[1]; } 275 else if (preg_match('/^[#](.*)$/',$t,$m)) { $tag = 'ID>>'.$m[1]; } 276 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 277 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 278 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')[.](.*)$/',$t,$m)) { $tag = $m[1].'>>CLASS>>'.$m[2]; } 279 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')\s*:NTH-CHILD\((.*)\)$/',$t,$m)) { $tag = $m[1].'>>SELECTORNTHCHILD>>'.$m[2]; } 280 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')[#](.*)$/',$t,$m)) { $tag = $m[1].'>>ID>>'.$m[2]; } 281 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 282 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 283 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')$/',$t)) { $tag= $t; } 284 if ($tag) $tmp[] = $tag; 285 else { break; } 286 } 287 } 288 289 if ($tag) { 290 $x = &$this->cascadeCSS; 291 foreach($tmp AS $tp) { $x = &$x[$tp]; } 292 $x = $this->array_merge_recursive_unique($x, $classproperties); 293 $x['depth'] = $level; 294 } 295 } 296 } 297 if ($pageselectors) { $this->mpdf->mirrorMargins = true; } 298 $properties = array(); 299 $values = array(); 300 $classproperties = array(); 301 } 302 } // end of if 303 //Remove CSS (tags and content), if any 304 $regexp = '/<style.*?>(.*?)<\/style>/si'; // it can be <style> or <style type="txt/css"> 305 $html = preg_replace($regexp,'',$html); 306//print_r($this->CSS); exit; 307//print_r($this->cascadeCSS); exit; 308 return $html; 309} 310