-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.php
106 lines (76 loc) · 2.81 KB
/
index.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
<?php
require 'vendor/autoload.php';
define("MLNS", "urn:ietf:params:xml:ns:metalink");
function parseLinkHeader($str){
$matched = preg_match('/<(.*?)>;\s*(.*)/', $str, $matches);
if($matched){
$url = $matches[1];
$attrs = explode(";", $matches[2]);
$attrs = array_map(function($attr){
$attr = trim($attr);
return explode("=", $attr);
}
, $attrs);
$attrs = array_reduce($attrs, function($attrs, $attr){
list($name,$val) = $attr;
$attrs[$name] = $val;
return $attrs;
}
, []);
return ['url' => $url, 'attr'=>$attrs];
}
}
$source = $_GET['url'];
if(empty($source)){
throw new \Exception("url missing");
}
$clientOpts = [
'allow_redirects' => false,
'verify' => false,
'debug' => false
];
$client = new \GuzzleHttp\Client($clientOpts);
$res = $client->request('HEAD', $source);
$linkHeaders = explode(", ", $res->getHeaderLine('link'));
$locationHeader = $res->getHeaderLine('location');
$res = $client->request('HEAD', $locationHeader);
if($res->getStatusCode() == 302){
$locationHeader = $res->getHeaderLine('location');
$res = $client->request('HEAD', $locationHeader);
}
$contentLengthHeader = $res->getHeaderLine('content-length');
$lastModifiedHeader = $res->getHeaderLine('last-modified');
$checksumtypes = ['md5', 'sha1', 'sha256'];
$checksums = array_reduce($checksumtypes, function($checksums, $checksumtype) use($client, $source){
$res = $client->request('GET', $source, ['query'=>$checksumtype, 'http_errors' => false]);
if($res->getStatusCode() == 200){
$checksums[$checksumtype] = explode(" ", $res->getBody()->getContents());
}
return $checksums;
}
, []);
$dom = new \DOMDocument("1.0", "UTF-8");
$dom->formatOutput = true;
$root = $dom->appendChild($dom->createElementNS(MLNS, 'metalink'));
$pub = $root->appendChild($dom->createElementNS(MLNS, 'published'));
$pub->nodeValue = date('c', strtotime($lastModifiedHeader));
$filename = basename(parse_url($locationHeader, PHP_URL_PATH));
$file = $root->appendChild($dom->createElementNS(MLNS, 'file'));
$file->setAttribute("name", $filename);
$size = $file->appendChild($dom->createElementNS(MLNS, 'size'));
$size->nodeValue = $contentLengthHeader;
$url = $file->appendChild($dom->createElementNS(MLNS, 'url'));
$url->nodeValue = $locationHeader;
foreach(array_map('parseLinkHeader', $linkHeaders ) as $linkInfo){
$url = $file->appendChild($dom->createElementNS(MLNS, 'url'));
$url->setAttribute('location', $linkInfo['attr']['geo']);
$url->setAttribute('priority', $linkInfo['attr']['pri']);
$url->nodeValue = $linkInfo['url'];
}
foreach($checksums as $chtype => $checksuminfo){
$hash = $file->appendChild($dom->createElementNS(MLNS, 'hash'));
$hash->setAttribute("type", $chtype);
$hash->nodeValue = $checksuminfo[0];
}
header("Content-Disposition: attachment; filename=\"{$filename}.meta4\"");
echo $dom->saveXML();