Newer
Older
<?php
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
* Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
\***************************************************************************/
if (!defined("_ECRIRE_INC_VERSION")) return;
//
// Cree au besoin la copie locale d'un fichier distant
// mode = 'test' - ne faire que tester
// mode = 'auto' - charger au besoin
// mode = 'force' - charger toujours (mettre a jour)
//
function copie_locale($source, $mode='auto') {
// Si copie_locale() est appele depuis l'espace prive
if (!_DIR_RESTREINT
AND strpos(_DIR_RACINE . $source, _DIR_IMG) === 0)
return _DIR_RACINE . $source;
$local = fichier_copie_locale($source);
// test d'existence du fichier
if ($mode == 'test')
return @file_exists(_DIR_RACINE.$local) ? $local : '';
// sinon voir si on doit le telecharger
if (($source != $local) AND (preg_match(',^\w+://,', $source))) {
if (($mode=='auto' AND !@file_exists($local))
OR $mode=='force') {
$contenu = recuperer_page($source);
if ($contenu) {
ecrire_fichier($local, $contenu);
// signaler au moteur de recherche qu'il peut reindexer ce doc
$id_document = spip_fetch_array(spip_query("SELECT id_document FROM spip_documents WHERE fichier='".addslashes($source)."'"));
$id_document = $id_document['id_document'];
if ($id_document) {
include_spip('inc/indexation');
marquer_indexer('document', $id_document);
}
}
else
return false;
}
}
return $local;
}
JamesRezo
a validé
function prepare_donnees_post($donnees, $boundary = '') {
if($boundary) {
// fabrique une chaine HTTP pour un POST avec boundary
$entete = "Content-Type: multipart/form-data; boundary=$boundary\r\n";
$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;
}
$chaine .= "\r\n--$boundary\r\n";
}
} else {
// fabrique une chaine HTTP simple pour un POST
$entete = 'Content-Type: application/x-www-form-urlencoded'."\r\n";
$chaine = array();
if (is_array($donnees)) {
foreach ($donnees as $cle => $valeur) {
if (is_array($valeur)) {
foreach ($valeur as $val2) {
$chaine[] = rawurlencode($cle).'='.urlencode($val2);
JamesRezo
a validé
}
} else {
$chaine[] = rawurlencode($cle).'='.urlencode($valeur);
JamesRezo
a validé
}
}
$chaine = implode('&', $chaine);
} else {
$chaine = $donnees;
}
}
return array($entete, $chaine);
}
//
// Recupere une page sur le net
// et au besoin l'encode dans le charset local
//
// options : get_headers si on veut recuperer les entetes
// taille_max : arreter le contenu au-dela (0 = seulement les entetes)
// Par defaut taille_max = 1Mo.
function recuperer_page($url, $munge_charset=false, $get_headers=false, $taille_max = 1048576, $datas='') {
// Accepter les URLs au format feed:// ou qui ont oublie le http://
$url = preg_replace(',^feed://,i', 'http://', $url);
if (!preg_match(',^[a-z]+://,i', $url)) $url = 'http://'.$url;
if ($taille_max == 0)
$get = 'HEAD';
else
$get = 'GET';
if (!empty($datas) && is_array($datas)) {
$get = 'POST';
JamesRezo
a validé
list($content_type, $postdata) = prepare_donnees_post($datas);
for ($i=0;$i<10;$i++) { // dix tentatives maximum en cas d'entetes 301...
list($f, $fopen) = init_http($get, $url);
// si on a utilise fopen() - passer a la suite
if ($fopen) {
spip_log('connexion via fopen');
break;
} else {
// Fin des entetes envoyees par SPIP
JamesRezo
a validé
fputs($f, $content_type);
fputs($f, 'Content-Length: '.strlen($postdata)."\r\n");
fputs($f, "\r\n".$postdata);
} else {
fputs($f,"\r\n");
}
// Reponse du serveur distant
$s = trim(fgets($f, 16384));
if (ereg('^HTTP/[0-9]+\.[0-9]+ ([0-9]+)', $s, $r)) {
$status = $r[1];
}
else return;
// Entetes HTTP de la page
$headers = '';
while ($s = trim(fgets($f, 16384))) {
$headers .= $s."\n";
if (eregi('^Location: (.*)', $s, $r)) {
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
$location = suivre_lien($url, $r[1]);
spip_log("Location: $location");
}
if (preg_match(",^Content-Encoding: .*gzip,i", $s))
$gz = true;
}
if ($status >= 300 AND $status < 400 AND $location)
$url = $location;
else if ($status != 200)
return;
else
break; # ici on est content
fclose($f);
$f = false;
}
}
// Contenu de la page
if (!$f) {
spip_log("ECHEC chargement $url");
return false;
}
$result = '';
while (!feof($f) AND strlen($result)<$taille_max)
$result .= fread($f, 16384);
fclose($f);
// Decompresser le flux
if ($gz)
$result = gzinflate(substr($result,10));
// Faut-il l'importer dans notre charset local ?
if ($munge_charset) {
$result = transcoder_page ($result, $headers);
}
return ($get_headers ? $headers."\n" : '').$result;
}
// Si on doit conserver une copie locale des fichiers distants, autant que ca
// soit a un endroit canonique -- si ca peut etre bijectif c'est encore mieux,
// mais la tout de suite je ne trouve pas l'idee, etant donne les limitations
// des filesystems
function nom_fichier_copie_locale($source, $extension) {
$dir = sous_repertoire(_DIR_IMG, 'distant'); # IMG/distant/
$dir2 = sous_repertoire($dir, $extension); # IMG/distant/pdf/
return $dir2 . substr(basename($source).'-'.md5($source),0,12).
substr(md5($source),0,4).'.'.$extension;
}
//
// Donne le nom de la copie locale de la source
//
function fichier_copie_locale($source) {
// Si c'est une image de IMG/ pas de souci
if (preg_match(',^'._DIR_IMG.',', $source))
return $source;
else if (preg_match(',^'._DIR_IMG_PACK.',', $source))
return $source;
// Si l'extension n'est pas precisee, aller la chercher dans la table
// des documents -- si la source n'est pas dans la table des documents,
// on ne fait rien
$t = spip_fetch_array(spip_query("SELECT id_type FROM spip_documents WHERE fichier='".addslashes($source)."' AND distant='oui'"));
if ($t) {
$t = spip_fetch_array(spip_query("SELECT extension FROM spip_types_documents WHERE id_type=".$t['id_type']));
if ($t)
return nom_fichier_copie_locale($source, $t['extension']);
}
}
// Recuperer les infos d'un document distant, sans trop le telecharger
function recuperer_infos_distantes($source, $max=0) {
$a = array();
// On va directement charger le debut des images et des fichiers html,
// de maniere a attrapper le maximum d'infos (titre, taille, etc). Si
// ca echoue l'utilisateur devra les entrer...
if ($headers = recuperer_page($source, false, true, $max)) {
list($headers, $a['body']) = split("\n\n", $headers, 2);
$t = preg_match(",\nContent-Type: *([^[:space:];]*),i",
"\n$headers", $regs);
if ($t) {
$mime_type = addslashes(trim($regs[1]));
$t = spip_fetch_array(spip_query("SELECT id_type,extension FROM spip_types_documents WHERE mime_type='$mime_type'"));
}
if ($t) {
spip_log("mime-type $mime_type ok");
$a['id_type'] = $t['id_type'];
$a['extension'] = $t['extension'];
} else {
# par defaut on retombe sur '.bin' si c'est autorise
spip_log("mime-type $mime_type inconnu");
$t = spip_fetch_array(spip_query("SELECT id_type,extension FROM spip_types_documents WHERE extension='bin'"));
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
if (!$t) return false;
$a['id_type'] = $t['id_type'];
$a['extension'] = $t['extension'];
}
if (preg_match(",\nContent-Length: *([^[:space:]]*),i",
"\n$headers", $regs))
$a['taille'] = intval($regs[1]);
}
// Echec avec HEAD, on tente avec GET
if (!$a AND !$max) {
spip_log("tente $source");
$a = recuperer_infos_distantes($source, 1024*1024);
}
// 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 ereg(",".$a['extension'].",",
','.$GLOBALS['meta']['formats_graphiques'].',')){
$a = recuperer_infos_distantes($source, 1024*1024);
}
else if ($a['body']) {
$a['fichier'] = nom_fichier_copie_locale($source, $a['extension']);
ecrire_fichier($a['fichier'], $a['body']);
$size_image = @getimagesize($a['fichier']);
$a['largeur'] = intval($size_image[0]);
$a['hauteur'] = intval($size_image[1]);
$a['type_image'] = true;
}
}
if ($mime_type == 'text/html') {
$page = recuperer_page($source, true, false, 1024*1024);
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
}
return $a;
}
//
// Demarre une transaction HTTP (s'arrete a la fin des entetes)
// retourne un descripteur de fichier
//
function init_http($get, $url, $refuse_gz=false) {
$http_proxy = $GLOBALS['meta']["http_proxy"];
if (!eregi("^http://", $http_proxy))
$http_proxy = '';
else
$via_proxy = " (proxy $http_proxy)";
spip_log("http $get $url$via_proxy");
$t = @parse_url($url);
$host = $t['host'];
if ($t['scheme'] == 'http') {
$scheme = 'http'; $scheme_fsock='';
} else {
$scheme = $t['scheme']; $scheme_fsock=$scheme.'://';
}
if (!($port = $t['port'])) $port = 80;
$query = $t['query'];
if (!($path = $t['path'])) $path = "/";
if ($http_proxy) {
$t2 = @parse_url($http_proxy);
$proxy_host = $t2['host'];
$proxy_user = $t2['user'];
$proxy_pass = $t2['pass'];
if (!($proxy_port = $t2['port'])) $proxy_port = 80;
$f = @fsockopen($proxy_host, $proxy_port);
} else
$f = @fsockopen($scheme_fsock.$host, $port);
if ($f) {
if ($http_proxy)
fputs($f, "$get $scheme://$host" . (($port != 80) ? ":$port" : "") . $path . ($query ? "?$query" : "") . " HTTP/1.0\r\n");
else
fputs($f, "$get $path" . ($query ? "?$query" : "") . " HTTP/1.0\r\n");
fputs($f, "Host: $host\r\n");
fputs($f, "User-Agent: SPIP-".$GLOBALS['spip_version_affichee']." (http://www.spip.net/)\r\n");
// Proxy authentifiant
if ($proxy_user) {
fputs($f, "Proxy-Authorization: Basic "
. base64_encode($proxy_user . ":" . $proxy_pass) . "\r\n");
}
// Referer = c'est nous !
if ($referer = $GLOBALS['meta']["adresse_site"])
fputs($f, "Referer: $referer/\r\n");
// On sait lire du gzip
if ($GLOBALS['flag_gz'] AND !$refuse_gz)
fputs($f, "Accept-Encoding: gzip\r\n");
}
// fallback : fopen
else if (!$GLOBALS['tester_proxy']) {
$f = @fopen($url, "rb");
$fopen = true;
}
// echec total
else {
$f = false;
}
return array($f, $fopen);
}
?>