[SPIP] ~maj v3.0.14-->v3.0.17
[ptitvelo/web/www.git] / www / ecrire / inc / distant.php
index c89d32d..e433095 100644 (file)
@@ -3,7 +3,7 @@
 /***************************************************************************\
  *  SPIP, Systeme de publication pour l'internet                           *
  *                                                                         *
- *  Copyright (c) 2001-2013                                                *
+ *  Copyright (c) 2001-2014                                                *
  *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
  *                                                                         *
  *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
@@ -12,7 +12,7 @@
 
 /**
  * Ce fichier gère l'obtention de données distantes
- * 
+ *
  * @package SPIP\Core\Distant
 **/
 if (!defined('_ECRIRE_INC_VERSION')) return;
@@ -20,8 +20,9 @@ if (!defined('_ECRIRE_INC_VERSION')) return;
 if (!defined('_INC_DISTANT_VERSION_HTTP')) define('_INC_DISTANT_VERSION_HTTP', "HTTP/1.0");
 if (!defined('_INC_DISTANT_CONTENT_ENCODING')) define('_INC_DISTANT_CONTENT_ENCODING', "gzip");
 if (!defined('_INC_DISTANT_USER_AGENT')) define('_INC_DISTANT_USER_AGENT', 'SPIP-' . $GLOBALS['spip_version_affichee'] . " (" . $GLOBALS['home_server'] . ")");
+if (!defined('_INC_DISTANT_MAX_SIZE')) define('_INC_DISTANT_MAX_SIZE',2097152);
 
-define('_REGEXP_COPIE_LOCALE', ',' . 
+define('_REGEXP_COPIE_LOCALE', ',' .
        preg_replace('@^https?:@', 'https?:', $GLOBALS['meta']['adresse_site'])
        . "/?spip.php[?]action=acceder_document.*file=(.*)$,");
 
@@ -150,10 +151,19 @@ function prepare_donnees_post($donnees, $boundary = '') {
                        $chaine = '';
                        if (is_array($donnees)) {
                                foreach ($donnees as $cle => $valeur) {
-                                       $chaine .= "\r\n--$boundary\r\n";
-                                       $chaine .= "Content-Disposition: form-data; name=\"$cle\"\r\n";
-                                       $chaine .= "\r\n";
-                                       $chaine .= $valeur;
+                                       if (is_array($valeur)) {
+                                               foreach ($valeur as $val2) {
+                                                       $chaine .= "\r\n--$boundary\r\n";
+                                                       $chaine .= "Content-Disposition: form-data; name=\"{$cle}[]\"\r\n";
+                                                       $chaine .= "\r\n";
+                                                       $chaine .= $val2;
+                                               }
+                                       } else {
+                                               $chaine .= "\r\n--$boundary\r\n";
+                                               $chaine .= "Content-Disposition: form-data; name=\"$cle\"\r\n";
+                                               $chaine .= "\r\n";
+                                               $chaine .= $valeur;
+                                       }
                                }
                                $chaine .= "\r\n--$boundary\r\n";
                        }
@@ -165,7 +175,7 @@ function prepare_donnees_post($donnees, $boundary = '') {
                                foreach ($donnees as $cle => $valeur) {
                                        if (is_array($valeur)) {
                                                foreach ($valeur as $val2) {
-                                                       $chaine[] = rawurlencode($cle).'='.rawurlencode($val2);
+                                                       $chaine[] = rawurlencode($cle).'[]='.rawurlencode($val2);
                                                }
                                        } else {
                                                $chaine[] = rawurlencode($cle).'='.rawurlencode($valeur);
@@ -206,7 +216,7 @@ function recuperer_page($url, $trans = false, $get_headers = false,
        $copy = (is_string($trans) AND strlen($trans)>5); // eviter "false" :-)
 
        if (is_null($taille_max))
-               $taille_max = $copy ? _COPIE_LOCALE_MAX_SIZE : 1048576;
+               $taille_max = $copy ? _COPIE_LOCALE_MAX_SIZE : _INC_DISTANT_MAX_SIZE;
 
        // Accepter les URLs au format feed:// ou qui ont oublie le http://
        $url = preg_replace(',^feed://,i', 'http://', $url);
@@ -239,7 +249,7 @@ function recuperer_page($url, $trans = false, $get_headers = false,
 // si $trans est null -> on ne veut que les headers
 // si $trans est une chaine, c'est un nom de fichier pour ecrire directement dedans
 // http://doc.spip.org/@recuperer_lapage
-function recuperer_lapage($url, $trans = false, $get = 'GET', $taille_max = 1048576, $datas = '', $refuser_gz = false, $date_verif = '', $uri_referer = ''){
+function recuperer_lapage($url, $trans = false, $get = 'GET', $taille_max = _INC_DISTANT_MAX_SIZE, $datas = '', $refuser_gz = false, $date_verif = '', $uri_referer = ''){
        // $copy = copier le fichier ?
        $copy = (is_string($trans) AND strlen($trans)>5); // eviter "false" :-)
 
@@ -255,6 +265,7 @@ function recuperer_lapage($url, $trans = false, $get = 'GET', $taille_max = 1048
                return false;
        }
 
+       $result = '';
        // Sauf en fopen, envoyer le flux d'entree
        // et recuperer les en-tetes de reponses
        if ($fopen)
@@ -263,14 +274,19 @@ function recuperer_lapage($url, $trans = false, $get = 'GET', $taille_max = 1048
                $headers = recuperer_entetes($f, $date_verif);
                if (is_numeric($headers)){
                        fclose($f);
-                       // Chinoisierie inexplicable pour contrer 
+                       // Chinoisierie inexplicable pour contrer
                        // les actions liberticides de l'empire du milieu
                        if ($headers){
                                spip_log("HTTP status $headers pour $url");
                                return false;
                        }
-                       elseif ($result = @file_get_contents($url))
-                               return array('', $result);
+                       $t = @parse_url($url);
+                       $host = $t['host'];
+                       if (!need_proxy($host)
+                               AND $result = @file_get_contents($url)){
+                               // on peuple les headers de vide et on continue
+                               $headers = array('');
+                       }
                        else
                                return false;
                }
@@ -290,9 +306,11 @@ function recuperer_lapage($url, $trans = false, $get = 'GET', $taille_max = 1048
        $gz = preg_match(",\bContent-Encoding: .*gzip,is", $headers) ?
                (_DIR_TMP . md5(uniqid(mt_rand())) . '.tmp.gz') : '';
 
-#      spip_log("entete ($trans $copy $gz)\n$headers"); 
-       $result = recuperer_body($f, $taille_max, $gz ? $gz : ($copy ? $trans : ''));
-       fclose($f);
+#      spip_log("entete ($trans $copy $gz)\n$headers");
+       if (!$result){
+               $result = recuperer_body($f, $taille_max, $gz ? $gz : ($copy ? $trans : ''));
+               fclose($f);
+       }
        if (!$result)
                return array($headers, $result);
 
@@ -311,7 +329,7 @@ function recuperer_lapage($url, $trans = false, $get = 'GET', $taille_max = 1048
 }
 
 // http://doc.spip.org/@recuperer_body
-function recuperer_body($f, $taille_max = 1048576, $fichier = ''){
+function recuperer_body($f, $taille_max = _INC_DISTANT_MAX_SIZE, $fichier = ''){
        $taille = 0;
        $result = '';
        $fp = false;
@@ -479,6 +497,7 @@ function fichier_copie_locale($source){
 #$a['taille'] = intval
 #$a['extension'] = chaine
 #$a['fichier'] = chaine
+#$a['mime_type'] = chaine
 
 // http://doc.spip.org/@recuperer_infos_distantes
 function recuperer_infos_distantes($source, $max = 0, $charger_si_petite_image = true){
@@ -558,18 +577,18 @@ function recuperer_infos_distantes($source, $max = 0, $charger_si_petite_image =
        // Echec avec HEAD, on tente avec GET
        if (!$a AND !$max){
                spip_log("tenter GET $source");
-               $a = recuperer_infos_distantes($source, 1024*1024);
+               $a = recuperer_infos_distantes($source, _INC_DISTANT_MAX_SIZE);
        }
 
        // S'il s'agit d'une image pas trop grosse ou d'un fichier html, on va aller
        // recharger le document en GET et recuperer des donnees supplementaires...
        if (preg_match(',^image/(jpeg|gif|png|swf),', $mime_type)){
                if ($max==0
-                       AND $a['taille']<1024*1024
+                       AND $a['taille']<_INC_DISTANT_MAX_SIZE
                                AND (strpos($GLOBALS['meta']['formats_graphiques'], $a['extension'])!==false)
                                        AND $charger_si_petite_image
                ){
-                       $a = recuperer_infos_distantes($source, 1024*1024);
+                       $a = recuperer_infos_distantes($source, _INC_DISTANT_MAX_SIZE);
                }
                else if ($a['body']){
                        $a['fichier'] = _DIR_RACINE . nom_fichier_copie_locale($source, $a['extension']);
@@ -592,11 +611,12 @@ function recuperer_infos_distantes($source, $max = 0, $charger_si_petite_image =
 
        if ($mime_type=='text/html'){
                include_spip('inc/filtres');
-               $page = recuperer_page($source, true, false, 1024*1024);
+               $page = recuperer_page($source, true, false, _INC_DISTANT_MAX_SIZE);
                if (preg_match(',<title>(.*?)</title>,ims', $page, $regs))
                        $a['titre'] = corriger_caracteres(trim($regs[1]));
                if (!$a['taille']) $a['taille'] = strlen($page); # a peu pres
        }
+       $a['mime_type']=$mime_type;
 
        return $a;
 }
@@ -659,7 +679,8 @@ function init_http($method, $url, $refuse_gz = false, $referer = '', $datas = ""
        $f = lance_requete($method, $scheme, $user, $host, $path, $port, $noproxy, $refuse_gz, $referer, $datas, $vers, $date);
        if (!$f){
                // fallback : fopen
-               if (!_request('tester_proxy')){
+               if (!need_proxy($host)
+                       AND !_request('tester_proxy')){
                        $f = @fopen($url, "rb");
                        spip_log("connexion vers $url par simple fopen");
                        $fopen = true;
@@ -679,10 +700,19 @@ function lance_requete($method, $scheme, $user, $host, $path, $port, $noproxy, $
        $http_proxy = need_proxy($host);
        if ($user) $user = urlencode($user[0]) . ":" . urlencode($user[1]);
 
+       $connect = "";
        if ($http_proxy){
-               $path = (($scheme=='ssl') ? 'https://' : "$scheme://")
-                       . (!$user ? '' : "$user@")
-                       . "$host" . (($port!=80) ? ":$port" : "") . $path;
+               if (defined('_PROXY_HTTPS_VIA_CONNECT') AND $scheme=="ssl"){
+                       $path_host = (!$user ? '' : "$user@") . $host . (($port!=80) ? ":$port" : "");
+                       $connect = "CONNECT " .$path_host." $vers\r\n"
+                               ."Host: $path_host\r\n"
+                               ."Proxy-Connection: Keep-Alive\r\n";
+               }
+               else {
+                       $path = (($scheme=='ssl') ? 'https://' : "$scheme://")
+                               . (!$user ? '' : "$user@")
+                               . "$host" . (($port!=80) ? ":$port" : "") . $path;
+               }
                $t2 = @parse_url($http_proxy);
                $first_host = $t2['host'];
                if (!($port = $t2['port'])) $port = 80;
@@ -692,9 +722,34 @@ function lance_requete($method, $scheme, $user, $host, $path, $port, $noproxy, $
        else
                $first_host = $noproxy . $host;
 
-       $f = @fsockopen($first_host, $port);
-       spip_log("Recuperer $path sur $first_host:$port par $f");
-       if (!$f) return false;
+       if ($connect){
+               $streamContext = stream_context_create(array('ssl' => array('verify_peer' => false, 'allow_self_signed' => true)));
+               $f = @stream_socket_client("tcp://$first_host:$port", $nError, $sError, 10, STREAM_CLIENT_CONNECT, $streamContext);
+               spip_log("Recuperer $path sur $first_host:$port par $f (via CONNECT)","connect");
+               if (!$f) return false;
+               stream_set_timeout($f, 10);
+
+               fputs($f, $connect);
+               fputs($f, "\r\n");
+               $res = fread($f, 1024);
+               if (!$res
+                 OR !count($res = explode(' ',$res))
+                 OR $res[1]!=='200'){
+                       spip_log("Echec CONNECT sur $first_host:$port","connect"._LOG_INFO_IMPORTANTE);
+                       fclose($f);
+                       return false;
+               }
+               // important, car sinon on lit trop vite et les donnees ne sont pas encore dispo
+               stream_set_blocking($f, true);
+               // envoyer le handshake
+               stream_socket_enable_crypto($f, true,   STREAM_CRYPTO_METHOD_SSLv23_CLIENT);
+               spip_log("OK CONNECT sur $first_host:$port","connect");
+       }
+       else {
+               $f = @fsockopen($first_host, $port);
+               spip_log("Recuperer $path sur $first_host:$port par $f");
+               if (!$f) return false;
+       }
 
        $site = $GLOBALS['meta']["adresse_site"];
 
@@ -714,4 +769,3 @@ function lance_requete($method, $scheme, $user, $host, $path, $port, $noproxy, $
        return $f;
 }
 
-?>