| [ Index ] |
|
Code source de SPIP 1.9.2c |
1 <?php 2 3 // 4 // Lit un document 'pdf' et extrait son contenu en texte brut 5 // 6 7 // NOTE : l'extracteur n'est pas oblige de convertir le contenu dans 8 // le charset du site, mais il *doit* signaler le charset dans lequel 9 // il envoie le contenu, de facon a ce qu'il soit converti au moment 10 // voulu ; dans le cas contraire le document sera lu comme s'il etait 11 // dans le charset iso-8859-1 12 13 // http://doc.spip.org/@extracteur_pdf 14 function extracteur_pdf($fichier, &$charset) { 15 16 /* methode tout PHP 17 $pdf = new Format_PDF; 18 $texte = $pdf->extraire_texte($fichier); 19 echo $texte; 20 exit; 21 */ 22 23 $charset = 'iso-8859-1'; 24 25 # metamail 26 @exec('metamail -d -q -b -c application/pdf '.escapeshellarg($fichier), $r, $e); 27 if (!$e) return @join(' ', $r); 28 29 # pdftotext 30 # http://www.glyphandcog.com/Xpdf.html 31 # l'option "-enc utf-8" peut echouer ... dommage ! 32 @exec('pdftotext '.escapeshellarg($fichier).' -', $r, $e); 33 if (!$e) return @join(' ', $r); 34 } 35 36 // Sait-on extraire ce format ? 37 // TODO: ici tester si les binaires fonctionnent 38 $GLOBALS['extracteur']['pdf'] = 'extracteur_pdf'; 39 40 41 42 43 44 45 // 46 // Methode tout PHP (a tester) 47 // 48 49 // http://doc.spip.org/@Format_PDF 50 class Format_PDF { 51 var $trans_chars; 52 var $flag_mono, $flag_brut; 53 54 // http://doc.spip.org/@convertir_caracteres 55 function convertir_caracteres($texte) { 56 if (!$this->trans_chars) { 57 // Caracteres speciaux 58 $this->trans_chars = array( 59 // ligatures typographiques (!) 60 chr(2) => 'fi', 61 chr(3) => 'fl', 62 chr(174) => 'fi', 63 chr(175) => 'fl', 64 // "e" accent aigu 65 chr(0) => chr(233) 66 ); 67 } 68 $texte = strtr($texte, $this->trans_chars); 69 // Caracteres non-ascii codes en octal 70 while (preg_match(',\\\\([0-7][0-7][0-7]),', $texte, $regs)) { 71 $c = chr(octdec($regs[1])); 72 $texte = str_replace($regs[0], $c, $texte); 73 $this->trans_chars[$regs[0]] = $c; 74 } 75 return $texte; 76 } 77 78 // http://doc.spip.org/@recoller_texte 79 function recoller_texte($stream) { 80 static $chars_voyelles, $chars_fusion, $chars_caps, $chars_nums, $bichars_fusion; 81 if (!$chars_voyelles) { 82 $chars_voyelles = array('a'=>1, 'e'=>1, 'i'=>1, 'o'=>1, 'u'=>1, 'y'=>1); 83 $chars_fusion = array('v'=>1, 'w'=>1, 'x'=>1, 'V'=>1, 'W'=>1, 'T'=>1); 84 $chars_caps = array('A'=>1, 'B'=>1, 'C'=>1, 'D'=>1, 'E'=>1, 'F'=>1, 'G'=>1, 85 'H'=>1, 'I'=>1, 'J'=>1, 'K'=>1, 'L'=>1, 'M'=>1, 'N'=>1, 86 'O'=>1, 'P'=>1, 'Q'=>1, 'R'=>1, 'S'=>1, 'T'=>1, 'U'=>1, 87 'V'=>1, 'W'=>1, 'X'=>1, 'Y'=>1, 'Z'=>1); 88 $chars_nums = array('0'=>1, '1'=>1, '2'=>1, '3'=>1, '4'=>1, '5'=>1, '6'=>1, '7'=>1, '8'=>1, '9'=>1); 89 $bichars_fusion = array('ve'=>1, 'vo'=>1, 'ev'=>1, 'ov'=>1, 90 'xe'=>1, 'xo'=>1, 'ox'=>1, 'ex'=>1, 91 'we'=>1, 'wo'=>1, 'ow'=>1, 'ew'=>1, 'ff'=>1); 92 } 93 // Longueur max pour limiter les erreurs d'extraction 94 $chaine_len = 140; 95 96 $stream = preg_split(",\)[^(]*\(,", $stream); 97 $extrait = ''; 98 $fini = false; 99 $this->flag_brut = false; 100 // Cette boucle est capable de basculer entre deux trois d'execution : 101 // - normal (plusieurs caracteres par chaine avec fusion) 102 // - brut (plusieurs caracteres par chaine sans fusion) 103 // - mono (un caractere par chaine) 104 while (1) { 105 if ($this->flag_mono) { 106 // Un caractere par chaine : fusion rapide 107 while (list(, $s) = each($stream)) { 108 if (strlen($s) != 1) { 109 if (strlen($s) < $chaine_len) $extrait .= $s; 110 $this->flag_mono = false; 111 break; 112 } 113 $extrait .= $s; 114 } 115 if ($this->flag_mono) break; 116 } 117 else if ($this->flag_brut) { 118 // Concatenation sans fusion 119 while (list(, $s) = each($stream)) $extrait .= $s; 120 break; 121 } 122 $prev_s = ''; 123 $prev_c = ''; 124 $prev_l = 0; 125 $nb_mono = 0; 126 $nb_brut = 0; 127 // Cas general : appliquer les regles de fusion 128 while (list(, $s) = each($stream)) { 129 $l = strlen($s); 130 if ($l >= $chaine_len) continue; 131 $c = $s{0}; 132 // Annulation de la cesure 133 if ($prev_c == '-') { 134 $extrait .= substr($prev_s, 0, -1); 135 } 136 else { 137 $extrait .= $prev_s; 138 $len_w = strpos($s.' ', ' '); 139 $prev_len_w = $prev_l - strrpos($prev_s, ' '); 140 $court = ($prev_len_w < 3 OR $len_w < 3); 141 // Heuristique pour separation des mots 142 if (/*$len_w == 1 OR $prev_len_w == 1 143 OR */($court AND ($chars_fusion[$prev_c] OR $chars_fusion[$c] 144 OR ($chars_caps[$prev_c] AND ($chars_caps[$c] OR $chars_nums[$c])))) 145 OR ($prev_c == 'f' AND $chars_voyelles[$c]) 146 OR $bichars_fusion[$prev_c.$c]) { 147 } 148 else $extrait .= ' '; 149 } 150 $prev_c = $s{$l - 1}; 151 $prev_s = $s; 152 $prev_l = $l; 153 // Detection du format mono-caractere 154 if ($l == 1) { 155 if (++$nb_mono >= 3) { 156 $this->flag_mono = true; 157 break; 158 } 159 } 160 else { 161 $nb_mono = 0; 162 if ($c == ' ' OR $prev_c == ' ') { 163 $this->flag_brut = true; 164 break; 165 } 166 } 167 } 168 $extrait .= $prev_s; 169 if (!$this->flag_mono && !$this->flag_brut) break; 170 } 171 return $extrait; 172 } 173 174 // http://doc.spip.org/@extraire_texte 175 function extraire_texte($fichier) { 176 177 $source_len = 1024*1024; 178 $stream_len = 20*1024; 179 $texte_len = 40*1024; 180 181 $f = fopen($fichier, "rb"); 182 if (!$f) die ("Fichier $fichier impossible a ouvrir"); 183 184 $in_stream = false; 185 186 // Decouper le fichier en objets 187 unset($objs); 188 $objs = fread($f, $source_len); 189 $objs = preg_split('/[\s>]endobj\s+/', $objs); 190 # echo "<h3>".count($objs)." objets présents dans le buffer</h3>"; 191 192 // Parcourir le fichier pour trouver les streams 193 reset($objs); 194 $n = count($objs); 195 for ($i = 0; $i < $n; $i++) { 196 $obj = $objs[$i]; 197 198 if (!$in_stream) { 199 // Stream (eviter les commentaires) 200 $ok = preg_match("/stream(\r\n?|\n)/", $obj); // version rapide d'abord 201 if ($ok) $ok = preg_match("/[\r\n](([^\r\n%]*[ \t>])*stream(\r\n?|\n))/", $obj, $regs); 202 if (!$ok) continue; 203 $p = strpos($obj, $regs[1]); 204 $t = substr($obj, $p + strlen($regs[1])); 205 $stream = ""; 206 $in_stream = true; 207 208 $obj_text = substr($obj, 0, $p + strlen($regs[1])); 209 210 // Parasites avant et apres 211 //$obj_text = preg_replace("/^\s+obj\s+/", "", $obj_text); 212 //$obj_text = preg_replace("/(\s+endobj)\s+.*$/", "\\1", $obj_text); 213 214 // Commentaires 215 $obj_text = preg_replace("/\\\\%/", ' ', $obj_text); 216 $obj_text = preg_replace("/%[^\r\n]*[\r\n]+/", '', $obj_text); 217 218 // Dictionnaire 219 $obj_dict = ""; 220 //if (ereg("<<(.*)>>", $obj_text, $regs)) 221 if (preg_match("/<<(.*)>>/s", $obj_text, $regs)) // bug ?! 222 $obj_dict = $regs[1]; 223 224 # echo "<hr>"; 225 # echo "Objet numéro $i<p>"; 226 # echo "<pre>".htmlspecialchars($obj_text)."</pre>"; 227 } 228 else { 229 $t = " endobj ".$obj; // approximation 230 } 231 unset($obj); 232 233 // Recoller les morceaux du stream (au cas ou un "obj" se trouvait en clair dans un stream) 234 if ($in_stream) { 235 if (!($p = strpos($t, "endstream")) && !($q = strpos($t, "endobj"))) { 236 $stream .= $t; 237 # echo "<span style='color: red'>Stream continué</span><p>"; 238 continue; 239 } 240 $in_stream = false; 241 if ($p) $stream .= substr($t, 0, $p); 242 else $stream .= substr($t, 0, $q); 243 unset($t); 244 245 // Decoder le contenu du stream 246 $encoding = ''; 247 if (preg_match(",/Filter\s*/([A-Za-z]+),", $obj_dict, $regs)) 248 $encoding = $regs[1]; 249 switch($encoding) { 250 case 'FlateDecode': 251 $stream = gzuncompress($stream); // pb avec certains PDFs !? 252 break; 253 case '': 254 break; 255 default: 256 $stream = ''; 257 } 258 /*if (preg_match("/\(d.marrage:\)/", $stream, $regs)) { 259 $fs = fopen("demarrage.txt", "w"); 260 fwrite($fs, $regs[0]); 261 fclose($fs); 262 exit; 263 }*/ 264 } 265 266 if (!$stream) continue; 267 268 # echo "Stream : ".strlen($stream)." octets<p>"; 269 270 // Eviter les fontes embarquees, etc. 271 if (preg_match(',^%!,', $stream)) { 272 unset($stream); 273 continue; 274 } 275 // Detection texte / binaire 276 $stream = substr($stream, 0, $stream_len); 277 $stream = str_replace('\\(', ",", $stream); 278 $stream = str_replace('\\)', ",", $stream); 279 $n1 = substr_count($stream, '('); 280 $n2 = substr_count($stream, ')'); 281 $freq = (substr_count($stream, ' ') + $n1 + $n2) / strlen($stream); 282 if ($freq < 0.04 || (!$n1 && !$n2)) { 283 # echo "no text (1)<p>"; 284 //echo htmlspecialchars($stream); 285 unset($stream); 286 continue; 287 } 288 $dev = abs($n1 - $n2) / ($n1 + $n2); 289 if ($dev > 0.05) { 290 # echo "no text (2)<p>"; 291 unset($stream); 292 continue; 293 } 294 // Extraction des chaines 295 if (strpos($stream, '<<') && strpos($stream, '>>')) 296 $stream = preg_replace(',<<.*?'.'>>,s', '', $stream); // bug avec preg 297 $stream = substr($stream, strpos($stream, '(') + 1); 298 $stream = substr($stream, 0, strrpos($stream, ')')); // ici un bug occasionnel... 299 $stream = $this->convertir_caracteres($stream); 300 $extrait = $this->recoller_texte($stream); 301 unset($stream); 302 $texte .= $extrait; 303 304 // Se limiter a une certaine taille de texte en sortie 305 if (strlen($texte) > $texte_len) { 306 $texte = substr($texte, 0, strrpos(substr($texte, 0, $texte_len), ' ')); 307 break; 308 } 309 } 310 311 fclose($f); 312 313 return $texte; 314 } 315 316 } // class 317 318 319 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Wed Nov 21 10:20:27 2007 | par Balluche grâce à PHPXref 0.7 |
|