PageRenderTime 49ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/spip/ecrire/inc/distant.php

https://github.com/eyeswebcrea/espace-couture-sittler.fr
PHP | 637 lines | 405 code | 88 blank | 144 comment | 117 complexity | 909435e4685a160e46764eca1ef103aa MD5 | raw file
Possible License(s): LGPL-2.1, GPL-3.0
  1. <?php
  2. /***************************************************************************\
  3. * SPIP, Systeme de publication pour l'internet *
  4. * *
  5. * Copyright (c) 2001-2011 *
  6. * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
  7. * *
  8. * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
  9. * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
  10. \***************************************************************************/
  11. if (!defined('_ECRIRE_INC_VERSION')) return;
  12. if (!defined('_INC_DISTANT_VERSION_HTTP')) define('_INC_DISTANT_VERSION_HTTP', "HTTP/1.0");
  13. if (!defined('_INC_DISTANT_CONTENT_ENCODING')) define('_INC_DISTANT_CONTENT_ENCODING', "gzip");
  14. if (!defined('_INC_DISTANT_USER_AGENT')) define('_INC_DISTANT_USER_AGENT', 'SPIP-' .$GLOBALS['spip_version_affichee']. " (" .$GLOBALS['home_server']. ")");
  15. //@define('_COPIE_LOCALE_MAX_SIZE',2097152); // poids (inc/utils l'a fait)
  16. //
  17. // Cree au besoin la copie locale d'un fichier distant
  18. // mode = 'test' - ne faire que tester
  19. // mode = 'auto' - charger au besoin
  20. // mode = 'modif' - Si deja present, ne charger que si If-Modified-Since
  21. // mode = 'force' - charger toujours (mettre a jour)
  22. //
  23. // Prend en argument un chemin relatif au rep racine, ou une URL
  24. // Renvoie un chemin relatif au rep racine, ou false
  25. //
  26. // http://doc.spip.org/@copie_locale
  27. function copie_locale($source, $mode='auto') {
  28. // si c'est la protection de soi-meme
  29. $reg = ',' . $GLOBALS['meta']['adresse_site']
  30. . "/?spip.php[?]action=acceder_document.*file=(.*)$,";
  31. if (preg_match($reg, $source, $local)) return substr(_DIR_IMG,strlen(_DIR_RACINE)) . urldecode($local[1]);
  32. $local = fichier_copie_locale($source);
  33. $localrac = _DIR_RACINE.$local;
  34. $t = ($mode=='force') ? false : @file_exists($localrac);
  35. // test d'existence du fichier
  36. if ($mode == 'test') return $t ? $local : '';
  37. // si $local = '' c'est un fichier refuse par fichier_copie_locale(),
  38. // par exemple un fichier qui ne figure pas dans nos documents ;
  39. // dans ce cas on n'essaie pas de le telecharger pour ensuite echouer
  40. if (!$local) return false;
  41. // sinon voir si on doit/peut le telecharger
  42. if ($local == $source OR !preg_match(',^\w+://,', $source))
  43. return $local;
  44. if ($mode=='modif' OR !$t) {
  45. $res = recuperer_page($source, $localrac,false,_COPIE_LOCALE_MAX_SIZE, '','',false, $t ? filemtime($localrac) : '');
  46. if (!$res) return $t ? $local : false;
  47. # spip_log ('ecrire copie locale '.$localrac." taille $res");
  48. // pour une eventuelle indexation
  49. pipeline('post_edition',
  50. array(
  51. 'args' => array(
  52. 'operation' => 'copie_locale',
  53. 'source' => $source,
  54. 'fichier' => $local
  55. ),
  56. 'data' => null
  57. )
  58. );
  59. }
  60. return $local;
  61. }
  62. // http://doc.spip.org/@prepare_donnees_post
  63. function prepare_donnees_post($donnees, $boundary = '') {
  64. // permettre a la fonction qui a demande le post de formater elle meme ses donnees
  65. // pour un appel soap par exemple
  66. // l'entete est separe des donnees par un double retour a la ligne
  67. // on s'occupe ici de passer tous les retours lignes (\r\n, \r ou \n) en \r\n
  68. if (is_string($donnees) && strlen($donnees)){
  69. $entete = "";
  70. // on repasse tous les \r\n et \r en simples \n
  71. $donnees = str_replace("\r\n","\n",$donnees);
  72. $donnees = str_replace("\r","\n",$donnees);
  73. // un double retour a la ligne signifie la fin de l'entete et le debut des donnees
  74. $p = strpos($donnees,"\n\n");
  75. if ($p!==FALSE){
  76. $entete = str_replace("\n","\r\n",substr($donnees,0,$p+1));
  77. $donnees = substr($donnees,$p+2);
  78. }
  79. $chaine = str_replace("\n","\r\n",$donnees);
  80. }
  81. else {
  82. /* boundary automatique */
  83. // Si on a plus de 500 octects de donnees, on "boundarise"
  84. if($boundary === '') {
  85. $taille = 0;
  86. foreach ($donnees as $cle => $valeur) {
  87. if (is_array($valeur)) {
  88. foreach ($valeur as $val2) {
  89. $taille += strlen($val2);
  90. }
  91. } else {
  92. // faut-il utiliser spip_strlen() dans inc/charsets ?
  93. $taille += strlen($valeur);
  94. }
  95. }
  96. if($taille>500) {
  97. $boundary = substr(md5(rand().'spip'), 0, 8);
  98. }
  99. }
  100. if(is_string($boundary) and strlen($boundary)) {
  101. // fabrique une chaine HTTP pour un POST avec boundary
  102. $entete = "Content-Type: multipart/form-data; boundary=$boundary\r\n";
  103. $chaine = '';
  104. if (is_array($donnees)) {
  105. foreach ($donnees as $cle => $valeur) {
  106. $chaine .= "\r\n--$boundary\r\n";
  107. $chaine .= "Content-Disposition: form-data; name=\"$cle\"\r\n";
  108. $chaine .= "\r\n";
  109. $chaine .= $valeur;
  110. }
  111. $chaine .= "\r\n--$boundary\r\n";
  112. }
  113. } else {
  114. // fabrique une chaine HTTP simple pour un POST
  115. $entete = 'Content-Type: application/x-www-form-urlencoded'."\r\n";
  116. $chaine = array();
  117. if (is_array($donnees)) {
  118. foreach ($donnees as $cle => $valeur) {
  119. if (is_array($valeur)) {
  120. foreach ($valeur as $val2) {
  121. $chaine[] = rawurlencode($cle).'='.rawurlencode($val2);
  122. }
  123. } else {
  124. $chaine[] = rawurlencode($cle).'='.rawurlencode($valeur);
  125. }
  126. }
  127. $chaine = implode('&', $chaine);
  128. } else {
  129. $chaine = $donnees;
  130. }
  131. }
  132. }
  133. return array($entete, $chaine);
  134. }
  135. //
  136. // Recupere une page sur le net
  137. // et au besoin l'encode dans le charset local
  138. //
  139. // options : get_headers si on veut recuperer les entetes
  140. // taille_max : arreter le contenu au-dela (0 = seulement les entetes ==>HEAD)
  141. // Par defaut taille_max = 1Mo.
  142. // datas, une chaine ou un tableau pour faire un POST de donnees
  143. // boundary, pour forcer l'envoi par cette methode
  144. // et refuser_gz pour forcer le refus de la compression (cas des serveurs orthographiques)
  145. // date_verif, un timestamp unix pour arreter la recuperation si la page distante n'a pas ete modifiee depuis une date donnee
  146. // uri_referer, preciser un referer different
  147. // Le second argument ($trans) :
  148. // * si c'est une chaine longue, alors c'est un nom de fichier
  149. // dans lequel on ecrit directement la page
  150. // * si c'est true/null ca correspond a une demande d'encodage/charset
  151. // http://doc.spip.org/@recuperer_page
  152. function recuperer_page($url, $trans=false, $get_headers=false,
  153. $taille_max = null, $datas='', $boundary='', $refuser_gz = false,
  154. $date_verif = '', $uri_referer = '') {
  155. $gz = false;
  156. // $copy = copier le fichier ?
  157. $copy = (is_string($trans) AND strlen($trans) > 5); // eviter "false" :-)
  158. if (is_null($taille_max))
  159. $taille_max = $copy ? _COPIE_LOCALE_MAX_SIZE : 1048576;
  160. // Accepter les URLs au format feed:// ou qui ont oublie le http://
  161. $url = preg_replace(',^feed://,i', 'http://', $url);
  162. if (!preg_match(',^[a-z]+://,i', $url)) $url = 'http://'.$url;
  163. if ($taille_max == 0)
  164. $get = 'HEAD';
  165. else
  166. $get = 'GET';
  167. if (!empty($datas)) {
  168. $get = 'POST';
  169. list($type, $postdata) = prepare_donnees_post($datas, $boundary);
  170. $datas = $type . 'Content-Length: '.strlen($postdata)."\r\n\r\n".$postdata;
  171. }
  172. // dix tentatives maximum en cas d'entetes 301...
  173. for ($i=0;$i<10;$i++) {
  174. $url = recuperer_lapage($url, $trans, $get, $taille_max, $datas, $refuser_gz, $date_verif, $uri_referer);
  175. if (!$url) return false;
  176. if (is_array($url)) {
  177. list($headers, $result) = $url;
  178. return ($get_headers ? $headers."\n" : '').$result;
  179. } else spip_log("recuperer page recommence sur $url");
  180. }
  181. }
  182. // args comme ci-dessus (presque)
  183. // retourne l'URL en cas de 301, un tableau (entete, corps) si ok, false sinon
  184. // si $trans est null -> on ne veut que les headers
  185. // si $trans est une chaine, c'est un nom de fichier pour ecrire directement dedans
  186. // http://doc.spip.org/@recuperer_lapage
  187. function recuperer_lapage($url, $trans=false, $get='GET', $taille_max = 1048576, $datas='', $refuser_gz = false, $date_verif = '', $uri_referer = '')
  188. {
  189. // $copy = copier le fichier ?
  190. $copy = (is_string($trans) AND strlen($trans) > 5); // eviter "false" :-)
  191. // si on ecrit directement dans un fichier, pour ne pas manipuler
  192. // en memoire refuser gz
  193. if ($copy)
  194. $refuser_gz = true;
  195. // ouvrir la connexion et envoyer la requete et ses en-tetes
  196. list($f, $fopen) = init_http($get, $url, $refuser_gz, $uri_referer, $datas, _INC_DISTANT_VERSION_HTTP, $date_verif);
  197. if (!$f) {
  198. spip_log("ECHEC init_http $url");
  199. return false;
  200. }
  201. // Sauf en fopen, envoyer le flux d'entree
  202. // et recuperer les en-tetes de reponses
  203. if ($fopen)
  204. $headers = '';
  205. else {
  206. $headers = recuperer_entetes($f, $date_verif);
  207. if (is_numeric($headers)) {
  208. fclose($f);
  209. // Chinoisierie inexplicable pour contrer
  210. // les actions liberticides de l'empire du milieu
  211. if ($headers) {
  212. spip_log("HTTP status $headers pour $url");
  213. return false;
  214. } elseif ($result = @file_get_contents($url))
  215. return array('', $result);
  216. else return false;
  217. }
  218. if (!is_array($headers)) { // cas Location
  219. fclose($f);
  220. include_spip('inc/filtres');
  221. return suivre_lien($url, $headers);
  222. }
  223. $headers = join('', $headers);
  224. }
  225. if ($trans === NULL) return array($headers, '');
  226. // s'il faut deballer, le faire via un fichier temporaire
  227. // sinon la memoire explose pour les gros flux
  228. $gz = preg_match(",\bContent-Encoding: .*gzip,is", $headers) ?
  229. (_DIR_TMP.md5(uniqid(mt_rand())).'.tmp.gz') : '';
  230. # spip_log("entete ($trans $copy $gz)\n$headers");
  231. $result = recuperer_body($f, $taille_max, $gz ? $gz : ($copy ? $trans : ''));
  232. fclose($f);
  233. if (!$result) return array($headers, $result);
  234. // Decompresser au besoin
  235. if ($gz) {
  236. $result = join('', gzfile($gz));
  237. supprimer_fichier($gz);
  238. }
  239. // Faut-il l'importer dans notre charset local ?
  240. if ($trans === true) {
  241. include_spip('inc/charsets');
  242. $result = transcoder_page ($result, $headers);
  243. }
  244. return array($headers, $result);
  245. }
  246. // http://doc.spip.org/@recuperer_body
  247. function recuperer_body($f, $taille_max=1048576, $fichier='')
  248. {
  249. $taille = 0;
  250. $result = '';
  251. if ($fichier){
  252. $fp = spip_fopen_lock($fichier, 'w',LOCK_EX);
  253. if (!$fp) return false;
  254. $result = 0; // on renvoie la taille du fichier
  255. }
  256. while (!feof($f) AND $taille<$taille_max){
  257. $res = fread($f, 16384);
  258. $taille += strlen($res);
  259. if ($fp){
  260. fwrite($fp,$res);
  261. $result = $taille;
  262. }
  263. else
  264. $result .= $res;
  265. }
  266. if ($fp)
  267. spip_fclose_unlock($fp);
  268. return $result;
  269. }
  270. // Lit les entetes de reponse HTTP sur la socket $f et retourne:
  271. // la valeur (chaine) de l'en-tete Location si on l'a trouvee
  272. // la valeur (numerique) du statut si different de 200, notamment Not-Modified
  273. // le tableau des entetes dans tous les autres cas
  274. // http://doc.spip.org/@recuperer_entetes
  275. function recuperer_entetes($f, $date_verif='')
  276. {
  277. $s = @trim(fgets($f, 16384));
  278. if (!preg_match(',^HTTP/[0-9]+\.[0-9]+ ([0-9]+),', $s, $r)) {
  279. return 0;
  280. }
  281. $status = intval($r[1]);
  282. $headers = array();
  283. $not_modif = $location = false;
  284. while ($s = trim(fgets($f, 16384))) {
  285. $headers[]= $s."\n";
  286. preg_match(',^([^:]*): *(.*)$,i', $s, $r);
  287. list(,$d, $v) = $r;
  288. if (strtolower(trim($d)) == 'location' AND $status >= 300 AND $status < 400) {
  289. $location = $v;
  290. }
  291. elseif ($date_verif AND ($d == 'Last-Modified')) {
  292. if ($date_verif>=strtotime($v)) {
  293. //Cas ou la page distante n'a pas bouge depuis
  294. //la derniere visite
  295. $not_modif = true;
  296. }
  297. }
  298. }
  299. if ($location) return $location;
  300. if ($status != 200 or $not_modif) return $status;
  301. return $headers;
  302. }
  303. // Si on doit conserver une copie locale des fichiers distants, autant que ca
  304. // soit a un endroit canonique -- si ca peut etre bijectif c'est encore mieux,
  305. // mais la tout de suite je ne trouve pas l'idee, etant donne les limitations
  306. // des filesystems
  307. // http://doc.spip.org/@nom_fichier_copie_locale
  308. function nom_fichier_copie_locale($source, $extension) {
  309. include_spip('inc/getdocument');
  310. $d = creer_repertoire_documents('distant'); # IMG/distant/
  311. $d = sous_repertoire($d, $extension); # IMG/distant/pdf/
  312. // on se place tout le temps comme si on etait a la racine
  313. if (_DIR_RACINE)
  314. $d = preg_replace(',^'.preg_quote(_DIR_RACINE).',', '', $d);
  315. $m = md5($source);
  316. return $d
  317. . substr(preg_replace(',[^\w-],', '', basename($source)).'-'.$m,0,12)
  318. . substr($m,0,4)
  319. . ".$extension";
  320. }
  321. //
  322. // Donne le nom de la copie locale de la source
  323. //
  324. // http://doc.spip.org/@fichier_copie_locale
  325. function fichier_copie_locale($source) {
  326. // Si c'est deja local pas de souci
  327. if (!preg_match(',^\w+://,', $source)) {
  328. if (_DIR_RACINE)
  329. $source = preg_replace(',^'.preg_quote(_DIR_RACINE).',', '', $source);
  330. return $source;
  331. }
  332. // optimisation : on regarde si on peut deviner l'extension dans l'url et si le fichier
  333. // a deja ete copie en local avec cette extension
  334. // dans ce cas elle est fiable, pas la peine de requeter en base
  335. $path_parts = pathinfo($source);
  336. $ext = $path_parts ? $path_parts['extension'] : '';
  337. if ($ext
  338. AND preg_match(',^\w+$,',$ext) // pas de php?truc=1&...
  339. AND $f=nom_fichier_copie_locale($source, $ext)
  340. AND file_exists(_DIR_RACINE . $f))
  341. return $f;
  342. // Si c'est deja dans la table des documents,
  343. // ramener le nom de sa copie potentielle
  344. $ext = sql_getfetsel("extension", "spip_documents", "fichier=" . sql_quote($source) . " AND distant='oui' AND extension <> ''");
  345. if ($ext) return nom_fichier_copie_locale($source, $ext);
  346. // voir si l'extension indiquee dans le nom du fichier est ok
  347. // et si il n'aurait pas deja ete rapatrie
  348. $ext = $path_parts ? $path_parts['extension'] : '';
  349. if ($ext AND sql_getfetsel("extension", "spip_types_documents", "extension=".sql_quote($ext))) {
  350. $f = nom_fichier_copie_locale($source, $ext);
  351. if (file_exists(_DIR_RACINE . $f))
  352. return $f;
  353. }
  354. // Ping pour voir si son extension est connue et autorisee
  355. $path_parts = recuperer_infos_distantes($source,0,false) ;
  356. $ext = $path_parts ? $path_parts['extension'] : '';
  357. if ($ext AND sql_getfetsel("extension", "spip_types_documents", "extension=".sql_quote($ext))) {
  358. return nom_fichier_copie_locale($source, $ext);
  359. }
  360. spip_log("pas de copie locale pour $source");
  361. }
  362. // Recuperer les infos d'un document distant, sans trop le telecharger
  363. #$a['body'] = chaine
  364. #$a['type_image'] = booleen
  365. #$a['titre'] = chaine
  366. #$a['largeur'] = intval
  367. #$a['hauteur'] = intval
  368. #$a['taille'] = intval
  369. #$a['extension'] = chaine
  370. #$a['fichier'] = chaine
  371. // http://doc.spip.org/@recuperer_infos_distantes
  372. function recuperer_infos_distantes($source, $max=0, $charger_si_petite_image = true) {
  373. # charger les alias des types mime
  374. include_spip('base/typedoc');
  375. global $mime_alias;
  376. $a = array();
  377. $mime_type = '';
  378. // On va directement charger le debut des images et des fichiers html,
  379. // de maniere a attrapper le maximum d'infos (titre, taille, etc). Si
  380. // ca echoue l'utilisateur devra les entrer...
  381. if ($headers = recuperer_page($source, false, true, $max, '', '', true)) {
  382. list($headers, $a['body']) = preg_split(',\n\n,', $headers, 2);
  383. if (preg_match(",\nContent-Type: *([^[:space:];]*),i", "\n$headers", $regs))
  384. $mime_type = (trim($regs[1]));
  385. else
  386. $mime_type = ''; // inconnu
  387. // Appliquer les alias
  388. while (isset($mime_alias[$mime_type]))
  389. $mime_type = $mime_alias[$mime_type];
  390. // Si on a un mime-type insignifiant
  391. // text/plain,application/octet-stream ou vide
  392. // c'est peut-etre que le serveur ne sait pas
  393. // ce qu'il sert ; on va tenter de detecter via l'extension de l'url
  394. // ou le Content-Disposition: attachment; filename=...
  395. $t = null;
  396. if (in_array($mime_type,array('text/plain','','application/octet-stream'))){
  397. if (!$t
  398. AND preg_match(',\.([a-z0-9]+)(\?.*)?$,', $source, $rext)) {
  399. $t = sql_fetsel("extension", "spip_types_documents", "extension=" . sql_quote($rext[1]));
  400. }
  401. if (!$t
  402. AND preg_match(",^Content-Disposition:\s*attachment;\s*filename=(.*)$,Uims",$headers,$m)
  403. AND preg_match(',\.([a-z0-9]+)(\?.*)?$,', $m[1], $rext)){
  404. $t = sql_fetsel("extension", "spip_types_documents", "extension=" . sql_quote($rext[1]));
  405. }
  406. }
  407. // Autre mime/type (ou text/plain avec fichier d'extension inconnue)
  408. if (!$t)
  409. $t = sql_fetsel("extension", "spip_types_documents", "mime_type=" . sql_quote($mime_type));
  410. // Toujours rien ? (ex: audio/x-ogg au lieu de application/ogg)
  411. // On essaie de nouveau avec l'extension
  412. if (!$t
  413. AND $mime_type != 'text/plain'
  414. AND preg_match(',\.([a-z0-9]+)(\?.*)?$,', $source, $rext)) {
  415. $t = sql_fetsel("extension", "spip_types_documents", "extension=" . sql_quote($rext[1]));
  416. }
  417. if ($t) {
  418. spip_log("mime-type $mime_type ok, extension ".$t['extension']);
  419. $a['extension'] = $t['extension'];
  420. } else {
  421. # par defaut on retombe sur '.bin' si c'est autorise
  422. spip_log("mime-type $mime_type inconnu");
  423. $t = sql_fetsel("extension", "spip_types_documents", "extension='bin'");
  424. if (!$t) return false;
  425. $a['extension'] = $t['extension'];
  426. }
  427. if (preg_match(",\nContent-Length: *([^[:space:]]*),i",
  428. "\n$headers", $regs))
  429. $a['taille'] = intval($regs[1]);
  430. }
  431. // Echec avec HEAD, on tente avec GET
  432. if (!$a AND !$max) {
  433. spip_log("tenter GET $source");
  434. $a = recuperer_infos_distantes($source, 1024*1024);
  435. }
  436. // S'il s'agit d'une image pas trop grosse ou d'un fichier html, on va aller
  437. // recharger le document en GET et recuperer des donnees supplementaires...
  438. if (preg_match(',^image/(jpeg|gif|png|swf),', $mime_type)) {
  439. if ($max == 0
  440. AND $a['taille'] < 1024*1024
  441. AND (strpos($GLOBALS['meta']['formats_graphiques'],$a['extension'])!==false)
  442. AND $charger_si_petite_image) {
  443. $a = recuperer_infos_distantes($source, 1024*1024);
  444. }
  445. else if ($a['body']) {
  446. $a['fichier'] = _DIR_RACINE . nom_fichier_copie_locale($source, $a['extension']);
  447. ecrire_fichier($a['fichier'], $a['body']);
  448. $size_image = @getimagesize($a['fichier']);
  449. $a['largeur'] = intval($size_image[0]);
  450. $a['hauteur'] = intval($size_image[1]);
  451. $a['type_image'] = true;
  452. }
  453. }
  454. // Fichier swf, si on n'a pas la taille, on va mettre 425x350 par defaut
  455. // ce sera mieux que 0x0
  456. if ($a['extension'] == 'swf'
  457. AND !$a['largeur']) {
  458. $a['largeur'] = 425;
  459. $a['hauteur'] = 350;
  460. }
  461. if ($mime_type == 'text/html') {
  462. include_spip('inc/filtres');
  463. $page = recuperer_page($source, true, false, 1024*1024);
  464. if(preg_match(',<title>(.*?)</title>,ims', $page, $regs))
  465. $a['titre'] = corriger_caracteres(trim($regs[1]));
  466. if (!$a['taille']) $a['taille'] = strlen($page); # a peu pres
  467. }
  468. return $a;
  469. }
  470. // http://doc.spip.org/@need_proxy
  471. function need_proxy($host)
  472. {
  473. $http_proxy = @$GLOBALS['meta']["http_proxy"];
  474. $http_noproxy = @$GLOBALS['meta']["http_noproxy"];
  475. $domain = substr($host,strpos($host,'.'));
  476. return ($http_proxy
  477. AND (strpos(" $http_noproxy ", " $host ") === false
  478. AND (strpos(" $http_noproxy ", " $domain ") === false)))
  479. ? $http_proxy : '';
  480. }
  481. //
  482. // Lance une requete HTTP avec entetes
  483. // retourne le descripteur sur lequel lire la reponse
  484. //
  485. // http://doc.spip.org/@init_http
  486. function init_http($method, $url, $refuse_gz=false, $referer = '', $datas="", $vers="HTTP/1.0", $date='') {
  487. $user = $via_proxy = $proxy_user = '';
  488. $fopen = false;
  489. $t = @parse_url($url);
  490. $host = $t['host'];
  491. if ($t['scheme'] == 'http') {
  492. $scheme = 'http'; $noproxy = '';
  493. } elseif ($t['scheme'] == 'https') {
  494. $scheme = 'ssl'; $noproxy = 'ssl://';
  495. if (!isset($t['port']) || !($port = $t['port'])) $t['port'] = 443;
  496. }
  497. else {
  498. $scheme = $t['scheme']; $noproxy = $scheme.'://';
  499. }
  500. if (isset($t['user']))
  501. $user = array($t['user'], $t['pass']);
  502. if (!isset($t['port']) || !($port = $t['port'])) $port = 80;
  503. if (!isset($t['path']) || !($path = $t['path'])) $path = "/";
  504. if (@$t['query']) $path .= "?" .$t['query'];
  505. $f = lance_requete($method, $scheme, $user, $host, $path, $port, $noproxy, $refuse_gz, $referer, $datas, $vers, $date);
  506. if (!$f) {
  507. // fallback : fopen
  508. if (!_request('tester_proxy')) {
  509. $f = @fopen($url, "rb");
  510. spip_log("connexion vers $url par simple fopen");
  511. $fopen = true;
  512. } else $f = false;// echec total
  513. }
  514. return array($f, $fopen);
  515. }
  516. // http://doc.spip.org/@lance_requete
  517. function lance_requete($method, $scheme, $user, $host, $path, $port, $noproxy, $refuse_gz=false, $referer = '', $datas="", $vers="HTTP/1.0", $date='') {
  518. $proxy_user = '';
  519. $http_proxy = need_proxy($host);
  520. if ($user) $user = urlencode($user[0]).":".urlencode($user[1]);
  521. if ($http_proxy) {
  522. $path = "$scheme://"
  523. . (!$user ? '' : "$user@")
  524. . "$host" . (($port != 80) ? ":$port" : "") . $path;
  525. $t2 = @parse_url($http_proxy);
  526. $first_host = $t2['host'];
  527. if (!($port = $t2['port'])) $port = 80;
  528. if ($t2['user'])
  529. $proxy_user = base64_encode($t2['user'] . ":" . $t2['pass']);
  530. } else $first_host = $noproxy.$host;
  531. $f = @fsockopen($first_host, $port);
  532. spip_log("Recuperer $path sur $first_host:$port par $f");
  533. if (!$f) return false;
  534. $site = $GLOBALS['meta']["adresse_site"];
  535. $req = "$method $path $vers\r\n"
  536. . "Host: $host\r\n"
  537. . "User-Agent: " . _INC_DISTANT_USER_AGENT . "\r\n"
  538. . ($refuse_gz ? '' : ("Accept-Encoding: " . _INC_DISTANT_CONTENT_ENCODING . "\r\n"))
  539. . (!$site ? '' : "Referer: $site/$referer\r\n")
  540. . (!$date ? '' : "If-Modified-Since: " . (gmdate("D, d M Y H:i:s", $date) ." GMT\r\n"))
  541. . (!$user ? '' : ("Authorization: Basic " . base64_encode($user) ."\r\n"))
  542. . (!$proxy_user ? '' : "Proxy-Authorization: Basic $proxy_user\r\n")
  543. . (!strpos($vers, '1.1') ? '' : "Keep-Alive: 300\r\nConnection: keep-alive\r\n");
  544. # spip_log("Requete\n$req");
  545. fputs($f, $req);
  546. fputs($f, $datas ? $datas : "\r\n");
  547. return $f;
  548. }
  549. ?>