[ Index ]
 

Code source de SPIP 1.9.2c

Accédez au Source d'autres logiciels libres

title

Body

[fermer]

/ecrire/inc/ -> distant.php (source)

   1  <?php
   2  
   3  /***************************************************************************\
   4   *  SPIP, Systeme de publication pour l'internet                           *
   5   *                                                                         *
   6   *  Copyright (c) 2001-2007                                                *
   7   *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
   8   *                                                                         *
   9   *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
  10   *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
  11  \***************************************************************************/
  12  
  13  if (!defined("_ECRIRE_INC_VERSION")) return;
  14  
  15  //
  16  // Cree au besoin la copie locale d'un fichier distant
  17  // mode = 'test' - ne faire que tester
  18  // mode = 'auto' - charger au besoin
  19  // mode = 'force' - charger toujours (mettre a jour)
  20  //
  21  // Prend en argument un chemin relatif au rep racine, ou une URL
  22  // Renvoie un chemin relatif au rep racine, ou false
  23  //
  24  // http://doc.spip.org/@copie_locale
  25  function copie_locale($source, $mode='auto') {
  26      $local = fichier_copie_locale($source);
  27  
  28      // test d'existence du fichier
  29      if ($mode == 'test')
  30          return @file_exists(_DIR_RACINE.$local) ? $local : '';
  31  
  32      // si $local = '' c'est un fichier refuse par fichier_copie_locale(),
  33      // par exemple un fichier qui ne figure pas dans nos documents ;
  34      // dans ce cas on n'essaie pas de le telecharger pour ensuite echouer
  35      if (!$local) return false;
  36  
  37      // sinon voir si on doit le telecharger
  38      if ($local != $source
  39      AND preg_match(',^\w+://,', $source)) {
  40          if (($mode=='auto' AND !@file_exists(_DIR_RACINE.$local))
  41          OR $mode=='force') {
  42              $contenu = recuperer_page($source);
  43              if ($contenu) {
  44                  ecrire_fichier(_DIR_RACINE.$local, $contenu);
  45  
  46                  // signaler au moteur de recherche qu'il peut reindexer ce doc
  47                  $id_document = spip_fetch_array(spip_query("SELECT id_document FROM spip_documents WHERE fichier=" . _q($source)));
  48                  $id_document = $id_document['id_document'];
  49                  if ($id_document) {
  50                      include_spip('inc/indexation');
  51                      marquer_indexer('spip_documents', $id_document);
  52                  }
  53              }
  54              else
  55                  return false;
  56          }
  57      }
  58  
  59      return $local;
  60  }
  61  
  62  // http://doc.spip.org/@prepare_donnees_post
  63  function prepare_donnees_post($donnees, $boundary = '') {
  64  
  65      // permettre a la fonction qui a demande le post de formater elle meme ses donnees
  66      // pour un appel soap par exemple
  67      // l'entete est separe des donnees par un double retour a la ligne
  68      // on s'occupe ici de passer tous les retours lignes (\r\n, \r ou \n) en \r\n
  69      if (is_string($donnees) && strlen($donnees)){
  70          $entete = "";
  71          // on repasse tous les \r\n et \r en simples \n
  72          $donnees = str_replace("\r\n","\n",$donnees);
  73          $donnees = str_replace("\r","\n",$donnees);
  74          // un double retour a la ligne signifie la fin de l'entete et le debut des donnees
  75          $p = strpos($donnees,"\n\n");
  76        if ($p!==FALSE){
  77            $entete = str_replace("\n","\r\n",substr($donnees,0,$p+1));
  78            $donnees = substr($donnees,$p+2);
  79        }
  80          $chaine = str_replace("\n","\r\n",$donnees);
  81    }
  82    else {
  83        /* boundary automatique */
  84        // Si on a plus de 500 octects de donnees, on "boundarise"
  85        if($boundary == '') {
  86          $taille = 0;
  87          foreach ($donnees as $cle => $valeur) {
  88                if (is_array($valeur)) {
  89                    foreach ($valeur as $val2) {
  90                $taille += strlen($val2);
  91              }
  92            } else {
  93              // faut-il utiliser spip_strlen() dans inc/charsets ?
  94              $taille += strlen($valeur);
  95            }
  96          }
  97          if($taille>500) {
  98            $boundary = substr(md5(rand().'spip'), 0, 8);
  99          }
 100        }
 101      
 102          if($boundary) {
 103              // fabrique une chaine HTTP pour un POST avec boundary
 104              $entete = "Content-Type: multipart/form-data; boundary=$boundary\r\n";
 105              $chaine = '';
 106              if (is_array($donnees)) {
 107                  foreach ($donnees as $cle => $valeur) {
 108                      $chaine .= "\r\n--$boundary\r\n";
 109                      $chaine .= "Content-Disposition: form-data; name=\"$cle\"\r\n";
 110                      $chaine .= "\r\n";
 111                      $chaine .= $valeur;
 112                  }
 113                  $chaine .= "\r\n--$boundary\r\n";
 114              }
 115          } else {
 116              // fabrique une chaine HTTP simple pour un POST
 117              $entete = 'Content-Type: application/x-www-form-urlencoded'."\r\n";
 118              $chaine = array();
 119              if (is_array($donnees)) {
 120                  foreach ($donnees as $cle => $valeur) {
 121                      if (is_array($valeur)) {
 122                          foreach ($valeur as $val2) {
 123                              $chaine[] = rawurlencode($cle).'='.rawurlencode($val2);
 124                          }
 125                      } else {
 126                          $chaine[] = rawurlencode($cle).'='.rawurlencode($valeur);
 127                      }
 128                  }
 129                  $chaine = implode('&', $chaine);
 130              } else {
 131                  $chaine = $donnees;
 132              }
 133          }
 134    }
 135      return array($entete, $chaine);
 136  }
 137  
 138  //
 139  // Recupere une page sur le net
 140  // et au besoin l'encode dans le charset local
 141  //
 142  // options : get_headers si on veut recuperer les entetes
 143  // taille_max : arreter le contenu au-dela (0 = seulement les entetes)
 144  // Par defaut taille_max = 1Mo.
 145  // datas, une chaine ou un tableau pour faire un POST de donnees
 146  // boundary, pour forcer l'envoi par cette methode
 147  // et refuser_gz pour forcer le refus de la compression (cas des serveurs orthographiques)
 148  // date_verif, un timestamp unix pour arreter la recuperation si la page distante n'a pas ete modifiee depuis une date donnee
 149  // uri_referer, preciser un referer different 
 150  // http://doc.spip.org/@recuperer_page
 151  function recuperer_page($url, $munge_charset=false, $get_headers=false,
 152      $taille_max = 1048576, $datas='', $boundary='', $refuser_gz = false,
 153      $date_verif = '', $uri_referer = '') {
 154        $gz = false;
 155  
 156      // Accepter les URLs au format feed:// ou qui ont oublie le http://
 157      $url = preg_replace(',^feed://,i', 'http://', $url);
 158      if (!preg_match(',^[a-z]+://,i', $url)) $url = 'http://'.$url;
 159  
 160      if ($taille_max == 0)
 161          $get = 'HEAD';
 162      else
 163          $get = 'GET';
 164  
 165      if (!empty($datas)) {
 166          $get = 'POST';
 167          list($content_type, $postdata) = prepare_donnees_post($datas);
 168      }
 169  
 170      for ($i=0;$i<10;$i++) {    // dix tentatives maximum en cas d'entetes 301...
 171          list($f, $fopen) = init_http($get, $url, $refuser_gz, $uri_referer);
 172  
 173          // si on a utilise fopen() - passer a la suite
 174          if ($fopen) {
 175              spip_log('connexion via fopen');
 176              break;
 177          } else {
 178              // Fin des entetes envoyees par SPIP
 179              if($get == 'POST') {
 180                  fputs($f, $content_type);
 181                  fputs($f, 'Content-Length: '.strlen($postdata)."\r\n");
 182                  fputs($f, "\r\n".$postdata);
 183              } else {
 184                  fputs($f,"\r\n");
 185              }
 186  
 187              // Reponse du serveur distant
 188              $s = trim(fgets($f, 16384));
 189              if (ereg('^HTTP/[0-9]+\.[0-9]+ ([0-9]+)', $s, $r)) {
 190                  $status = $r[1];
 191              }
 192              else return;
 193  
 194              // Entetes HTTP de la page
 195              $headers = '';
 196              while ($s = trim(fgets($f, 16384))) {
 197                  $headers .= $s."\n";
 198                  if (eregi('^Location: (.*)', $s, $r)) {
 199                      include_spip('inc/filtres');
 200                      $location = suivre_lien($url, $r[1]);
 201                      spip_log("Location: $location");
 202                  }
 203                  if ($date_verif AND preg_match(',^Last-Modified: (.*),', $s, $r)) {
 204                      if(strtotime($date_verif)>=strtotime($r[1])) {
 205                          //Cas ou la page distante n'a pas bouge depuis
 206                          //la derniere visite
 207                          return $status;
 208                      }
 209                  }
 210                  if (preg_match(",^Content-Encoding: .*gzip,i", $s))
 211                      $gz = true;
 212              }
 213              if ($status >= 300 AND $status < 400 AND $location)
 214                  $url = $location;
 215              else if ($status != 200)
 216                  return false;
 217              else
 218                  break; # ici on est content
 219              fclose($f);
 220              $f = false;
 221          }
 222      }
 223  
 224      // Contenu de la page
 225      if (!$f) {
 226          spip_log("ECHEC chargement $url");
 227          return false;
 228      }
 229  
 230      $result = '';
 231      while (!feof($f) AND strlen($result)<$taille_max)
 232          $result .= fread($f, 16384);
 233      fclose($f);
 234  
 235      // Decompresser le flux
 236      if ($gz AND $result)
 237          $result = gzinflate(substr($result,10));
 238  
 239      // Faut-il l'importer dans notre charset local ?
 240      if ($munge_charset) {
 241          include_spip('inc/charsets');
 242          $result = transcoder_page ($result, $headers);
 243      }
 244  
 245      return ($get_headers ? $headers."\n" : '').$result;
 246  }
 247  
 248  
 249  // Si on doit conserver une copie locale des fichiers distants, autant que ca
 250  // soit a un endroit canonique -- si ca peut etre bijectif c'est encore mieux,
 251  // mais la tout de suite je ne trouve pas l'idee, etant donne les limitations
 252  // des filesystems
 253  // http://doc.spip.org/@nom_fichier_copie_locale
 254  function nom_fichier_copie_locale($source, $extension) {
 255      $dir = sous_repertoire(_DIR_IMG, 'distant'); # IMG/distant/
 256      $dir2 = sous_repertoire($dir, $extension);         # IMG/distant/pdf/
 257      $chemin = $dir2 . substr(preg_replace(',[^\w-],', '', basename($source)).'-'.md5($source),0,12).
 258          substr(md5($source),0,4).'.'.$extension;
 259  
 260      // on se place tout le temps comme si on etait a la racine
 261      if (_DIR_RACINE)
 262          $chemin = preg_replace(',^'.preg_quote(_DIR_RACINE).',', '', $chemin);
 263  
 264      return $chemin;
 265  }
 266  
 267  //
 268  // Donne le nom de la copie locale de la source
 269  //
 270  // http://doc.spip.org/@fichier_copie_locale
 271  function fichier_copie_locale($source) {
 272      // Si c'est une image locale pas de souci
 273      if (!preg_match(',^\w+://,', $source)) {
 274          if (_DIR_RACINE)
 275              $source = preg_replace(',^'.preg_quote(_DIR_RACINE).',', '', $source);
 276          return $source;
 277      }
 278  
 279      $extension = "";
 280      // Chercher d'abord le doc dans la table des documents, pour se baser sur son type reel
 281      $t = spip_fetch_array(spip_query("SELECT id_type FROM spip_documents WHERE fichier=" . _q($source) . " AND distant='oui'"));
 282      if ($t) {
 283          $t = spip_fetch_array(spip_query("SELECT extension FROM spip_types_documents WHERE id_type=".$t['id_type']));
 284          if ($t)
 285              $extension = $t['extension'];
 286      }
 287      
 288      // si la source n'est pas dans la table des documents, on regarde si son extension est connue et autorisee
 289      if (!strlen($extension)) {
 290          $path_parts = pathinfo($source);
 291          if (isset($path_parts['extension']) && strlen($path_parts['extension'])){
 292              // verifier que c'est un type autorise
 293              $t = spip_fetch_array(spip_query("SELECT extension FROM spip_types_documents WHERE extension="._q($path_parts['extension'])));
 294              if ($t)
 295                  $extension = $t['extension'];
 296          }
 297      }
 298      
 299      if (strlen($extension))
 300          return nom_fichier_copie_locale($source, $extension);
 301  }
 302  
 303  
 304  // Recuperer les infos d'un document distant, sans trop le telecharger
 305  // http://doc.spip.org/@recuperer_infos_distantes
 306  function recuperer_infos_distantes($source, $max=0) {
 307  
 308      $a = array();
 309      $mime_type = '';
 310      // On va directement charger le debut des images et des fichiers html,
 311      // de maniere a attrapper le maximum d'infos (titre, taille, etc). Si
 312      // ca echoue l'utilisateur devra les entrer...
 313      if ($headers = recuperer_page($source, false, true, $max)) {
 314          list($headers, $a['body']) = split("\n\n", $headers, 2);
 315          $t = preg_match(",\nContent-Type: *([^[:space:];]*),i",
 316                  "\n$headers", $regs);
 317          if ($t) {
 318            $mime_type = (trim($regs[1]));
 319            $t = spip_fetch_array(spip_query("SELECT id_type,extension FROM spip_types_documents WHERE mime_type=" . _q($mime_type)));
 320          }
 321          if ($t) {
 322              spip_log("mime-type $mime_type ok");
 323              $a['id_type'] = $t['id_type'];
 324              $a['extension'] = $t['extension'];
 325          } else {
 326              # par defaut on retombe sur '.bin' si c'est autorise
 327              spip_log("mime-type $mime_type inconnu");
 328              $t = spip_fetch_array(spip_query("SELECT id_type,extension FROM spip_types_documents WHERE extension='bin'"));
 329              if (!$t) return false;
 330              $a['id_type'] = $t['id_type'];
 331              $a['extension'] = $t['extension'];
 332          }
 333  
 334          if (preg_match(",\nContent-Length: *([^[:space:]]*),i",
 335              "\n$headers", $regs))
 336              $a['taille'] = intval($regs[1]);
 337      }
 338  
 339      // Echec avec HEAD, on tente avec GET
 340      if (!$a AND !$max) {
 341      spip_log("tente $source");
 342          $a = recuperer_infos_distantes($source, 1024*1024);
 343      }
 344  
 345      // S'il s'agit d'une image pas trop grosse ou d'un fichier html, on va aller
 346      // recharger le document en GET et recuperer des donnees supplementaires...
 347      if (preg_match(',^image/(jpeg|gif|png|swf),', $mime_type)) {
 348          if ($max == 0
 349              AND $a['taille'] < 1024*1024
 350          AND ereg(",".$a['extension'].",",
 351          ','.$GLOBALS['meta']['formats_graphiques'].',')){
 352              $a = recuperer_infos_distantes($source, 1024*1024);
 353          }
 354          else if ($a['body']) {
 355              $a['fichier'] = nom_fichier_copie_locale($source, $a['extension']);
 356              ecrire_fichier($a['fichier'], $a['body']);
 357              $size_image = @getimagesize($a['fichier']);
 358              $a['largeur'] = intval($size_image[0]);
 359              $a['hauteur'] = intval($size_image[1]);
 360              $a['type_image'] = true;
 361          }
 362      }
 363      
 364      if ($mime_type == 'text/html') {
 365          include_spip('inc/filtres');
 366          $page = recuperer_page($source, true, false, 1024*1024);
 367          if(preg_match(',<title>(.*?)</title>,ims', $page, $regs)) 
 368              $a['titre'] = corriger_caracteres(trim($regs[1]));
 369              if (!$a['taille']) $a['taille'] = strlen($page); # a peu pres
 370      }
 371  
 372      return $a;
 373  }
 374  
 375  
 376  //
 377  // Demarre une transaction HTTP (s'arrete a la fin des entetes)
 378  // retourne un descripteur de fichier
 379  //
 380  // http://doc.spip.org/@init_http
 381  function init_http($get, $url, $refuse_gz=false, $uri_referer = '') {
 382      $via_proxy = ''; $proxy_user = ''; $fopen = false;
 383      $http_proxy = $GLOBALS['meta']["http_proxy"];
 384      if (!eregi("^http://", $http_proxy))
 385          $http_proxy = '';
 386      else
 387          $via_proxy = " (proxy $http_proxy)";
 388  
 389      spip_log("http $get $url$via_proxy");
 390  
 391      $t = @parse_url($url);
 392      $host = $t['host'];
 393      if ($t['scheme'] == 'http') {
 394          $scheme = 'http'; $scheme_fsock='';
 395      } else {
 396          $scheme = $t['scheme']; $scheme_fsock=$scheme.'://';
 397      }
 398      if (!isset($t['port']) || !($port = $t['port'])) $port = 80;
 399      $query = $t['query'];
 400      if (!isset($t['path']) || !($path = $t['path'])) $path = "/";
 401  
 402      if ($http_proxy) {
 403          $t2 = @parse_url($http_proxy);
 404          $proxy_host = $t2['host'];
 405          $proxy_user = $t2['user'];
 406          $proxy_pass = $t2['pass'];
 407          if (!($proxy_port = $t2['port'])) $proxy_port = 80;
 408          $f = @fsockopen($proxy_host, $proxy_port);
 409      } else
 410          $f = @fsockopen($scheme_fsock.$host, $port);
 411  
 412      if ($f) {
 413          if ($http_proxy)
 414              fputs($f, "$get $scheme://$host" . (($port != 80) ? ":$port" : "") . $path . ($query ? "?$query" : "") . " HTTP/1.0\r\n");
 415          else
 416              fputs($f, "$get $path" . ($query ? "?$query" : "") . " HTTP/1.0\r\n");
 417  
 418          fputs($f, "Host: $host\r\n");
 419          fputs($f, "User-Agent: SPIP-".$GLOBALS['spip_version_affichee']." (http://www.spip.net/)\r\n");
 420  
 421          // Proxy authentifiant
 422          if ($proxy_user) {
 423              fputs($f, "Proxy-Authorization: Basic "
 424              . base64_encode($proxy_user . ":" . $proxy_pass) . "\r\n");
 425          }
 426          // Referer = c'est nous !
 427          if ($referer = $GLOBALS['meta']["adresse_site"]) {
 428              $referer .= '/'.$uri_referer;
 429              fputs($f, "Referer: $referer\r\n");
 430          }
 431  
 432          // On sait lire du gzip
 433          if ($GLOBALS['flag_gz'] AND !$refuse_gz)
 434              fputs($f, "Accept-Encoding: gzip\r\n");
 435  
 436      }
 437      // fallback : fopen
 438      else if (!$GLOBALS['tester_proxy']) {
 439          $f = @fopen($url, "rb");
 440          $fopen = true;
 441      }
 442      // echec total
 443      else {
 444          $f = false;
 445      }
 446  
 447      return array($f, $fopen);
 448  }
 449  
 450  ?>


Généré le : Wed Nov 21 10:20:27 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics