fixed the directory making bits for the downloader...
[glcas.git] / plugins / repo.php
1 <?php
2 $URL_HANDLERS["*"] = "GLCASRepo";
3 global $CRON_CLASSES;
4 $CRON_CLASSES["GLCASRepo"] = "GLCASRepo";
5
6 class GLCASRepo {
7         function __construct($config)
8         {
9                 $this->config = $config;
10                 if($this->config->getConfigVar("storagelocation") == false) {
11                         global $WEB_ROOT_FS;
12                         $storloc = "$WEB_ROOT_FS/../var/glcas/cache/";
13                         if(!file_exists($storloc)) mkdir($storloc);
14                         $this->config->setConfigVar("storagelocation", realpath($storloc));
15                         $this->config->saveConfig();
16                         error_log("set storage location, $storloc");
17                 }
18         }
19         
20         function cron()
21         {
22                 //echo "<pre>";
23                 $uconf = unserialize($this->config->getConfigVar("repodata"));
24                 $repostore = $this->config->getConfigVar("storagelocation");
25                 //print_r($uconf);
26                 //echo "</pre>";
27                 
28                 foreach($uconf as $rkey => $repo) {
29                         echo "Repo $rkey: ".$repo["desc"]."<br>";
30                         if(!isset($repo["expiretime"])) {
31                                 echo " - Expire time not set, setting to 2 days by default<br>";
32                                 $uconf[$rkey]["expiretime"] = 2;
33                                 $repo["expiretime"] = 2;
34                                 $this->config->setConfigVar("repodata", serialize($uconf));
35                                 $this->config->saveConfig();                            
36                         }
37                         
38                         if(file_exists("$repostore/$rkey/repodata/repoupdate.lock")) {
39                                 echo " - <font color=\"red\">Repo locked for update</font><br>";
40                                 
41                         }
42                         
43                         // we still do this next bit, even if its locked because it may be a stray file
44                         echo " - Expire time is ".$repo["expiretime"]." days, checking repo<br>";
45                         error_log("checking $repostore/$rkey/repodata/repomd.xml");
46                         $tdiff = time() - filemtime("$repostore/$rkey/repodata/repomd.xml");
47                         $maxtdiff = $repo["expiretime"] * 24 * 3600;
48                         if($tdiff > $maxtdiff) {
49                                 echo " - <font color=\"green\">updating repo</font><br>";
50                                 $this->updateRepo($rkey);
51                         } else {
52                                 echo " - not updating repo<br>";
53                         }
54                 }
55         }
56
57         function go($url)
58         {
59                 error_log("repo:go called");
60
61                 // figure out what we're doing
62                 switch($url) {
63                         case "list":
64                                 GLCASpageBuilder($this, "body");
65                                 break;
66                         default:
67                                 $this->getRepoForUrl($url);
68                 }
69         }
70
71         function body($url)
72         {
73                 // this is how this will work
74                 //$this->decodeUrl();
75                 if(strncasecmp("list", $url, 4)==0) {
76                         echo "i am the repo list";
77                         return;
78                 }
79                 echo "i am the repo, $url";
80         }
81
82
83         // TODO: rework this function
84         /*
85         * What i need to do is have a downloader function
86         * that can cope with lots of different shit
87         * but thats a pipe dream
88         *
89         * what *THIS* function needs to do is
90         * 1) figure out the repo
91         * 2) figure out the file in the repo
92         * 2.1) if its a directory, go to print directory
93         * 3) if the file exists, give it to the user (if a range is specified give the user the range)
94         * 4) if the file does not exist
95         *    - check if a tmp file exists
96         *    - attempt to get an exclusive flock
97         *    - if flock fails, donwload in progress
98         *    - if flock succeeds, truncate file and re-start download
99         *    - if a range request was made, send the range once available
100         *    - if range not available, sleep for 5 and check again.
101         *
102         * I dont want to code this from scratch, but i probably need to
103         */
104         function getRepoForUrl($url)
105         {
106                 $xurl = split("[/,]", $url);
107
108                 // first get the config
109                 $uconf = unserialize($this->config->getConfigVar("repodata"));
110                 $repostore = $this->config->getConfigVar("storagelocation");
111
112                 // preset matched to -1
113                 $matched = -1;
114
115                 // first we check for /repo/repoid as a url
116                 $startat = 0;
117                 if($xurl[0] == "repo") {
118                         $repid = $xurl[1];
119                         error_log("trying to get repo for repoid, $repid");
120                         if(isset($uconf[$repid])) {
121                                 $matched = ((int)($repid));
122                                 error_log("set matched, $matched, $repid");
123                                 $startat +=2;
124                         }
125                 }
126
127                 // now check for a prefix match
128                 $prematch = false;
129                 if($matched < 0) foreach($uconf as $key => $var) {
130                         $pre = $var["prefix"];
131                                 
132                         if($pre!="") {
133                                 //echo "Checking pre $pre against ".$xurl[0]."\n";
134                                 if(strcasecmp($pre, $xurl[0])==0) {
135                                         //echo "Matched pre\n";
136                                         $prematch = true;
137                                         $startat++;
138                                 }
139                         }
140                 }
141
142                 // next, check for a short url match
143                 if($matched < 0) foreach($uconf as $key => $var) {
144                         // if we matched a pre, then we check against the second url component
145                                 
146                         $short = $var["shorturl"];
147                                 
148                         if($short!="") {
149                                 //echo "Checking short $short against ".$xurl[$startat]."\n";
150                                 if(strcasecmp($xurl[$startat], $short)==0) {
151                                         //echo "Matched\n";
152                                         $matched = $key;
153                                         $startat++;
154                                 }
155                         }
156                 }
157
158                 // TODO: this deterministic bit
159                 // so far nothing has matched - what this next bit needs to do is try and "Determine" a repo from url
160                 // for eg, if a user gets /fedora/x86_64/os we need to return something appropriate
161                 if($matched < 0) {
162                         echo "No such repo<br>";
163                         header("HTTP/1.0 404 Not Found");
164                         return;
165                 }
166
167
168                 // something was matched, so now we reconstruct the file component of the url
169                 $file = "/";
170                 if(count($xurl) > $startat) for($i=$startat; $i < count($xurl); $i++) {
171                         $file .= "/".$xurl[$i];
172                 }
173
174                 // so, the ultimate url for the file we need is:
175                 $actualfile = "$repostore/$matched/$file";
176                 error_log("Atcualfile is $actualfile");
177
178                 // if its a directory, lets do a print
179                 if(is_dir($actualfile)) {
180                         $this->printDir($actualfile, $file, $url);
181                         return;
182                 }
183
184                 // check if the file exists and serve it up
185                 if(file_exists($actualfile) && !file_exists("$actualfile.size")) {
186                         $this->serveUpFile($actualfile, $matched);
187                         return;
188                 } else {
189                         // the file does not exist, we now need to go into "download" mode
190                         $remoteurl = $uconf[$matched]["url"]."/$file";
191                         $this->downloadAndServe($actualfile, $matched, $remoteurl);
192                         return;
193                 }
194         }
195
196         function serveUpFile($actualfile, $repoid)
197         {
198                 $uconf = unserialize($this->config->getConfigVar("repodata"));
199                 $repostore = $this->config->getConfigVar("storagelocation");
200
201                 // figure out the range header garbage that centos/redhat send
202                 if(isset($_SERVER["HTTP_RANGE"])) {
203                         // we're using ranges - screw you stupid installer
204                         $pr_range = preg_split("/[:\-=, ]+/", $_SERVER["HTTP_RANGE"]);
205                                 
206                         // cut up ranges
207                         $rangestart = $pr_range[1];
208                         $rangelength = $pr_range[2] - $pr_range[1] +1;
209                         $rangestr = $pr_range[1]."-".$pr_range[2];
210                         error_log("going ranges at $rangestart, $rangelength,".$rangesa[1].",".$rangesb[0]);
211                                 
212                         // now spit some headers
213                         header("HTTP/1.1 206 Partial Content");
214                         header("Content-Length: ".$rangelength);
215                                 
216
217                         header("Content-Range: bytes $rangestr/".filesize($actualfile));
218                                 
219                         // determine mime type
220                         $type = mime_content_type($actualfile);
221                                 
222                         // set mime type header
223                         header("Content-type: $type");
224                                 
225                         // open the local file (TODO: error check)
226                         $localfile = fopen($actualfile, "r");
227                         fseek($localfile, $rangestart, SEEK_SET);
228                                 
229                         // read in the data, god i hope its not big
230                         $data = fread($localfile, $rangelength);
231                                 
232                         // lastly, send data
233                         echo $data;
234                         flush();
235                                 
236                         // and close the file
237                         fclose($localfile);
238                         return;
239                 } else {
240
241                         // we're not using range's - good on you installer thingy
242                         header("Content-Length: ".filesize($actualfile));
243
244                         // set the mime type header
245                         $type = mime_content_type($actualfile);
246                         header("Content-type: $type");
247                                 
248                         // open the local file
249                         $localfile = fopen($actualfile, "r");
250                         if(!$localfile) {
251                                 error_log("normal upload went barf");
252                                 return;
253                         }
254                                 
255                         // iterate over its length, send 8k at a time
256                         while(!feof($localfile)) {
257                                 // read and send data
258                                 $data = fread($localfile, 32768);
259                                 echo $data;
260
261                                 // flush so the client sees the data
262                                 flush();
263                         }
264                                 
265                         // close the file
266                         fclose($localfile);
267                         return;
268                 }
269         }
270
271         // TODO: this is the function im working on
272         // the alternative to this function is that if a file is in the process of being
273         // downloaded, we simply serve from upstream... not a good idea tho unless we create
274         // a local proxy right here - this function is a race condition waiting to be had
275         // lets hope its a good one!
276         function downloadAndServe($filename, $repoid, $remoteurl)
277         {
278
279                 $this->startDownload($filename, $remoteurl);
280
281                 // give the proc a minute to get going
282                 sleep(2);
283                 clearstatcache();
284
285                 // get the configurations we need
286                 $uconf = unserialize($this->config->getConfigVar("repodata"));
287                 $repostore = $this->config->getConfigVar("storagelocation");
288
289
290
291                 // determine if we're ranged
292                 $ranged = false;
293                 $rangestart = 0;
294                 $rangelength = 0;
295                 $rangestr="";
296                 if(isset($_SERVER["HTTP_RANGE"])) {
297                         // we're using ranges - screw you stupid installer
298                                 
299                         $pr_range = preg_split("/[:\-=, ]+/", $_SERVER["HTTP_RANGE"]);
300                         error_log("got range ".$_SERVER["HTTP_RANGE"]." and ".print_r($pr_range, true));
301                                 
302                         // cut up ranges
303                         $rangestart = $pr_range[1];
304                         $rangelength = $pr_range[2] - $pr_range[1] +1;
305                         $rangestr = $pr_range[1]."-".$pr_range[2];
306                         error_log("going ranges at $rangestart, $rangelength, $rangestr");
307                         $ranged = true;
308                 }
309
310                 // open the local files
311
312                 // now, lets determine what state we're in
313                 // we're either - getting and sending
314                 // watching and sending
315                 // or a range (Getting and sending)
316                 // or a range (watching and sending)
317                 // TODO: it may be advicable to start the download as a seperate cli process rather then something goin on here
318                 // so it definitely cant be interrupted.
319                 
320                 // check for a 404 file and wait 2 if it exists - i should really check the timestamp for an updated
321                 // file, but thats too much effort for now: TODO: check timestamp on 404 file
322                 $slept = 0;
323                 while(!file_exists("$filename")) {
324                         clearstatcache();
325                         sleep(1);
326                         $slept += 1;
327                         error_log("Sleeping waiting for file");
328                         
329                         // if 404 file exists, we wait much less time
330                         if(file_exists("$filename.404") && $slept > 2) {
331                                 header("HTTP/1.0 404 Not Found");
332                                 return;
333                         }
334                         if($slept > 10) {
335                                 header("HTTP/1.0 404 Not Found");
336                                 return;
337                         } 
338                 }
339                 
340                 clearstatcache();
341                 if(is_dir($filename)) {
342                         
343                         header("Location: ".$_SERVER["REQUEST_URI"]."/");
344                         return;
345                 }
346                         
347
348                 // first, getting and sending - this is easy.
349                 if (!$ranged) {
350                                 
351                         $localfile = fopen($filename, "r");
352                                 
353                         // this is where the fun starts - but this one isnt too bad.
354                         error_log("OTHERDOWNLOAD: im another downloader, please work");
355                         if(file_exists("$filename.size")) $fsize = file_get_contents("$filename.size");
356                         else $fsize = filesize($filename);
357                         header("Content-Length: $fsize");
358                         $sgotten = 0;
359                         while(!feof($localfile)) {
360                                 $data = fread($localfile, 2048);
361                                 if(!$data) {
362                                         error_log("dollardata is pair shaped");
363                                 } else {
364                                         $sgotten += strlen($data);
365                                         if($sgotten > $fsize) {
366                                                 error_log("went plop at sgotten, $sgotten, $fsize");
367                                                 return;
368                                         }
369                                         echo $data;
370                                         flush();
371                                 }
372                         }
373                         fclose($localfile);
374                                 
375                         // need to think about this in pseudo code.
376                         // 1. close the file and wait for it to get to $sgotten + 2048 or $fsize
377                         $cursize = filesize($filename);                         
378                                 
379                         $upload_finished = false;
380                         while(!$upload_finished) {
381                                 while($cursize < $fsize && $cursize < ($sgotten+2048)) {
382                                         clearstatcache();
383                                         error_log("OTHERDOWNLOAD: halt, $cursize, $sgotten, $fsize");
384                                         // sleep until the the filesize is greater then what we're up to, or until the file is finished
385                                         sleep(1);
386                                         $cursize = filesize($filename);
387                                 }
388
389                                 error_log("OTHERDOWNLOAD: continue, $sgotten, $fsize");
390                                 // reopen local file - if it stopped existing, we need to deal with that
391                                 $localfile = fopen($filename, "r");
392
393                                 // UG, we need to ff, how could i forget that
394                                 fseek($localfile, $sgotten);
395
396                                 if(!$localfile) {
397                                         error_log("OTHERDOWNLOAD: something went plop");
398                                         return;
399                                 }
400
401                                 // now loop on the file until we have it at an eof
402                                 while(!feof($localfile)) {
403                                         $data = fread($localfile, 512);
404                                         if(!$data) {
405                                                 error_log("OTHERDOWNLOAD: dollar data went plop");
406                                         } else {
407                                                 $sgotten += strlen($data);
408                                                 echo $data;
409                                                 flush();
410                                         }
411                                 }
412                                 fclose($localfile);
413
414                                 if($sgotten >= $fsize) {
415                                         if($sgotten > $fsize) error_log("OTHERDOWNLOADER: finished but $sgotten, $fsize doesnt make senze");
416                                         $upload_finished = true;
417                                 }
418                                 // and we're done
419
420                         }
421                         error_log("OTHERDOWNLOADER: done with");
422                                 
423                         return;
424
425
426                                 
427                                 
428                         // Next painful bit
429                 } else {
430                         // and here too, yay, someone else is doing the
431                         // download, but we're the retards getting a range
432                         $sgotten = 0;
433                                 
434                         $sgatlen = $rangestart+$rangelength;
435                                 
436                         // the problem is here
437                         error_log("Downloader: going ranged as other");
438                         clearstatcache();
439                         if(file_exists($filename.".tmp.data.deleteme.size")) $contentlen = file_get_contents($filename.".tmp.data.deleteme.size");
440                         else $contentlen = filesize($filename);
441                         $contenttype = mime_content_type($filename);
442                         header("HTTP/1.1 206 Partial Content");
443                         header("Content-Length: $rangelength");
444                         header("Content-Range: bytes $rangestr/$contentlen");
445                         $contenttype = "Content-Type: application/x-rpm";
446                         
447                         error_log("$contenttype");
448                         header("$contenttype");
449                         
450                         
451                         clearstatcache();
452                                 
453                                 
454                         // first we wait until the file reaches $rangestart
455                         while(filesize("$filename") < $rangestart) {
456                                 sleep(1);
457                         }
458                                 
459                         // then we open the file and ff to rangestart
460                         $localfile = fopen($filename, "r");
461                         fseek($localfile, $rangestart);
462                                 
463                         $sgotten = 0;
464                         // need to think about this in pseudo code.
465                         // 1. close the file and wait for it to get to $sgotten + 2048 or $fsize
466                         $cursize = filesize($filename);
467                                 
468                                 
469                         $upload_finished = false;
470                         while(!$upload_finished) {
471                                 while($cursize < $sgatlen && $cursize < ($sgotten+2048)) {
472                                         clearstatcache();
473                                         error_log("OTHERDOWNLOAD: halt, $cursize, $sgotten, $contentlen");
474                                         // sleep until the the filesize is greater then what we're up to, or until the file is finished
475                                         sleep(1);
476                                         $cursize = filesize($filename);
477                                 }
478
479                                 error_log("OTHERDOWNLOAD: continue, $sgotten, $contentlen");
480                                 // reopen local file - if it stopped existing, we need to deal with that
481                                 $localfile = fopen($filename, "r");
482
483                                 // UG, we need to ff, how could i forget that
484                                 fseek($localfile, $sgotten+$rangestart);
485
486                                 if(!$localfile) {
487                                         error_log("OTHERDOWNLOAD: something went plop");
488                                         return;
489                                 }
490
491                                 // now loop on the file until we have it at sgatlen
492                                 while(!feof($localfile) && $sgotten < $rangelength) {
493                                         $left = $rangelength - $sgotten;
494                                         if($left > 512) $lenget = 512;
495                                         else $lenget = $left;
496                                         $data = fread($localfile, $lenget);
497                                         if(!$data) {
498                                                 error_log("OTHERDOWNLOAD: dollar data went plop");
499                                         } else {
500                                                 $sgotten += strlen($data);
501                                                 echo $data;
502                                                 flush();
503                                         }
504                                 }
505                                 fclose($localfile);
506
507                                 if($sgotten >= $rangelength) {
508                                         if($sgotten > $rangelength) error_log("OTHERDOWNLOADER: finished but $sgotten, $fsize doesnt make senze");
509                                         $upload_finished = true;
510                                 }
511                                 // and we're done
512
513                         }
514                         error_log("OTHERDOWNLOADER: done with");
515                                 
516                         return;
517                                 
518                 }
519
520
521                 return;
522         }
523
524         function startDownload($file, $url)
525         {
526                 
527                 error_log("background downloader, start");
528                 global $WEB_ROOT_FS, $URL_HANDLERS, $BASE_URL;
529                 if(file_exists("$WEB_ROOT_FS/../bin/downloadfile.php")) {
530                         $scall = "/usr/bin/php $WEB_ROOT_FS/../bin/downloadfile.php '$url' '$file' > /tmp/dllog 2>&1 &";
531                         system($scall);
532                 } else {
533                         error_log("cant find download helper... dieing");
534                 }
535         }
536
537         // this is a nightmare
538         function getRepoForUrlOld($url)
539         {
540                 // the way we breakdown a url is to explode it
541                 $xurl = split("[/,]", $url);
542
543                 // we first check if [0] is a prefix
544                 // if now, we check for it being a shorturl (lets just do that for now)
545                 $uconf = unserialize($this->config->getConfigVar("repodata"));
546                 $repostore = $this->config->getConfigVar("storagelocation");
547
548                 $matched = -1;
549
550                 // first we check for /repo/repoid as a url
551                 $startat = 0;
552                 if($xurl[0] == "repo") {
553                         $repid = $xurl[1];
554                         error_log("trying to get repo for repoid, $repid");
555                         if(isset($uconf[$repid])) {
556                                 $matched = ((int)($repid));
557                                 error_log("set matched, $matched, $repid");
558                                 $startat +=2;
559                         }
560                 }
561
562
563                 $prematch = false;
564                 if($matched < 0) foreach($uconf as $key => $var) {
565                         $pre = $var["prefix"];
566                                 
567                         if($pre!="") {
568                                 //echo "Checking pre $pre against ".$xurl[0]."\n";
569                                 if(strcasecmp($pre, $xurl[0])==0) {
570                                         //echo "Matched pre\n";
571                                         $prematch = true;
572                                         $startat++;
573                                 }
574                         }
575                 }
576
577
578                 if($matched < 0) foreach($uconf as $key => $var) {
579                         // if we matched a pre, then we check against the second url component
580                                 
581                         $short = $var["shorturl"];
582                                 
583                         if($short!="") {
584                                 //echo "Checking short $short against ".$xurl[$startat]."\n";
585                                 if(strcasecmp($xurl[$startat], $short)==0) {
586                                         //echo "Matched\n";
587                                         $matched = $key;
588                                         $startat++;
589                                 }
590                         }
591                 }
592
593                 if($matched < 0) {
594                         echo "No such repo<br>";
595                         return;
596                 }
597
598
599                 // now we find an actual file
600                 $file = "/";
601                 if(count($xurl) > $startat) for($i=$startat; $i < count($xurl); $i++) {
602                         $file .= "/".$xurl[$i];
603                 }
604
605                 // now we want to find repostore/$matched/$file;
606                 $actualfile = "$repostore/$matched/$file";
607                 error_log("Atcualfile is $actualfile");
608                 //echo "Start file for $actualfile\n";
609
610                 // first check any directories in $file are in existence
611                 $splfile = explode("/", $file);
612                 if(count($splfile) > 1) {
613                         $tomake = "$repostore/$matched/";
614                         for($i = 0; $i < count($splfile)-1; $i++) {
615                                 $tomake .= "/".$splfile[$i];
616                                 //error_log("making directory $tomake");
617                                 if(!is_dir($tomake)) mkdir($tomake);
618                         }
619                 }
620
621                 $reqhead = print_r($_REQUEST, true);
622                 $sevhead = print_r($_SERVER, true);
623
624                 error_log("req $reqhead");
625                 error_log("sev $sevhead");
626
627                 $rangestart = -1;
628                 $rangelength = -1;
629                 $rangesstr = "";
630                 if(isset($_SERVER["HTTP_RANGE"])) {
631                         // oh shit
632                         $rangesa = explode("=", $_SERVER["HTTP_RANGE"]);
633                         $rangesb = explode(",", $rangesa[1]);
634                         $rangesstr = $rangesb[0];
635                         $ranges = explode("-", $rangesb[0]);
636                         $rangestart = $ranges[0];
637                         $rangelength = $ranges[1] - $ranges[0] +1;
638                         error_log("going ranges at $rangestart, $rangelength,".$rangesa[1].",".$rangesb[0]);
639                 }
640
641                 // i have to support http_range cause REDHAT/CENTOS IS annoying as all hell. christ, why do this?
642                 if(is_file($actualfile)) {
643                         // file is stored locally, away we go
644                         if($rangelength != -1) {
645                                 header("HTTP/1.1 206 Partial Content");
646                                 header("Content-Length: ".$rangelength);
647                                 header("Content-Range: bytes $rangesstr/".filesize($actualfile));
648                                 //header("Content-Length: ".filesize($actualfile));
649                         } else {
650                                 header("Content-Length: ".filesize($actualfile));
651                         }
652                         $type = mime_content_type($actualfile);
653                         header("Content-type: $type");
654                         $localfile = fopen($actualfile, "r");
655                         if($rangestart!=-1) fseek($localfile, $rangestart, SEEK_SET);
656                         while(!feof($localfile)) {
657                                 // cant make this high cause centos is crap
658                                 if($rangelength!=-1) {
659                                         $data = fread($localfile, $rangelength);
660                                         error_log("data size was ".strlen($data));
661                                 } else {
662                                         $data = fread($localfile, 2048);
663                                 }
664
665                                 echo $data;
666                                 flush();
667
668                                 if($rangelength!=-1) {
669                                         fclose($localfile);
670                                         exit(0);
671                                 }
672                         }
673                         fclose($localfile);
674                 } else if(is_dir($actualfile)) {
675                         //echo "in dir for $actualfile\n";
676                         // here we print the contents of the directory
677                         $this->printDir($actualfile, $file, $url);
678                 } else {
679                         // ok, get the file
680                         //echo "in getcheck\n";
681                         $remotefile = $uconf[$matched]["url"]."/$file";
682                                 
683                         // TODO: i should get remote contents with fopen/fread/fwrite as
684                         // it should be more memory conservative and we can push to the end client
685                         // straight away
686                         ignore_user_abort(true);
687                         $rf = fopen($remotefile, "r");
688                         error_log("attempting to get remote file $remotefile");
689
690                                 
691                         // hopefully this works. if we get a 30x message, it means we tried to get a directory
692                         // i cant think of another way of dealing with it - but this is UGLY
693                         // also get content length and content type
694                         $clen = 0;
695                         foreach($http_response_header as $key => $val) {
696                                 if(preg_match("/HTTP.*30[1-9].*/", $val)) {
697                                         error_log("got a 30x, must be a directory");
698                                         mkdir($actualfile);
699                                         header("Location: ".$_SERVER["REQUEST_URI"]."/");
700                                         return;
701                                 }
702                                 // get content length form upstream and print
703                                 if(preg_match("/^Content-Length:.*/", $val)) {
704                                         $clen = $val;
705                                         header($val);
706                                 }
707                                 // get content type from upstream and print
708                                 if(preg_match("/^Content-Type:.*/", $val)) {
709                                         header($val);
710                                 }
711                         }
712                         //error_log("repsonse: $http_response_header");
713                         if(!$rf) {
714                                 // return 404
715                                 header("HTTP/1.0 404 Not Found");
716                         } else {
717                                 $localfile = fopen($actualfile.".tmp.data.deleteme", "w");
718                                 $localsizefile = fopen($actualfile.".tmp.data.deleteme.size", "w");
719                                 fwrite($localsizefile, "$clen");
720                                 fclose($localsizefile);
721                                 while(!feof($rf)) {
722                                         $data = fread($rf, 8192);
723                                         echo $data;
724                                         fwrite($localfile, $data);
725                                         flush();
726                                 }
727                                 fclose($localfile);
728                                 fclose($rf);
729                                 rename($actualfile.".tmp.data.deleteme", $actualfile);
730                                 //error_log("got actualfile, tried to save as $actualfile, did it work?");
731                         }
732                 }
733
734                 //echo "got ".$file." for $url which is $actualfile\n";
735
736                 //echo "</html></pre>";
737         }
738
739         function printDir($dir, $localfile, $baseurl)
740         {
741                 $localfile = preg_replace("/\/\/+/", "/", $localfile);
742                 $uri = $_SERVER["REQUEST_URI"];
743                 $content = "";
744                 if(is_dir($dir)) {
745                         $content .= "<html><head><title>Index of $localfile</title></head><body><h1>Index of $localfile</h1>";
746                         $content .= "<table>";
747                         $dh = opendir($dir);
748                         while(($file = readdir($dh))!==false) {
749                                 if($file != "." && $file != "..") $content .= "<tr><td><a href=\"$uri/$file\">$file</a></td></tr>";
750                         }
751                         $content .= "</table></body></html>";
752                                 
753                         GLCASpageBuilder(null, null, $content);
754                                 
755                 } else return false;
756         }
757
758         function getRepoDetailsYum($url, $ismirrorlist=false)
759         {
760                 $actionurl = $url."/repodata/repomd.xml";
761
762                 error_log("Getting for action of $actionurl");
763
764                 $ld = file_get_contents($actionurl);
765
766                 // so here we try and get what this repository provides (os, version, arch), for yum this
767                 // should come straight off the url... i.e. centos/6.0/os/x86_64/ (centos, 6.0, base os, 64bit arch)
768
769                 if(!$ld) return false;
770
771                 // ok, now we tokenize the url and try and guess at the content
772                 $spurl = explode("/", $url);
773
774                 // first, find the OS
775                 $kos = getKnownOSList();
776                 $glt["OS"] = "unknown";
777                 $glt["verison"] = "unknown";
778                 $glt["arch"] = "unknown";
779                 $glt["other"] = "unknown";
780                 foreach($spurl as $comp) {
781                                 
782                         // find a name
783                         foreach($kos["os"]["short"] as $kosname => $koslong) {
784                                 //error_log("Comparing $kosname and $koslong with $comp");
785                                 if(strcasecmp($kosname, $comp) == 0) {
786                                         //error_log("got $kosname, $koslong for $comp in $url");
787                                         //echo "<pre>inone\n"; print_r($koslong); echo "</pre>";
788                                         $glt["OS"] = $koslong;
789                                 }
790                         }
791                                 
792                         // find a version, we assume its going to be something [numbers] and a . (optional)
793                         if(preg_match("/^[0-9.]+$/", $comp)>0) {
794                                 //error_log("version match of $comp");
795                                 $glt["version"] = $comp;
796                         }
797                                 
798                         // now architecture, this can be either i?86 or x86_64 - can also be arm or otherwise, but lets just go with this for now
799                         foreach($kos["arch"] as $archinter => $archname ) {
800                                 //error_log("Comparing $archinter, $archname with $comp");
801                                 if(strcasecmp($archname, $comp) == 0) {
802                                         //error_log("arch match of $archname with $comp");
803                                         $glt["arch"] = $archname;
804                                 }
805                         }
806                                 
807                         // other is a bt harder, we really have to guess at this one
808                         if(strcasecmp("os", $comp) == 0) $glt["other"] = "OS";
809                         if(strcasecmp("update", $comp) == 0) $glt["other"] = "Updates";
810                         if(strcasecmp("updates", $comp) == 0) $glt["other"] = "Updates";
811                         if(strcasecmp("everything", $comp) == 0) $glt["other"] = "OS";
812                 }
813
814                         
815                 return $glt;
816         }
817
818         function deleteRepo($rkey)
819         {
820                 $uconf = $this->config->getConfigVar("repodata");
821                 $repostore = $this->config->getConfigVar("storagelocation");
822
823                 if($uconf !== false) {
824                         $conf = unserialize($uconf);
825                         foreach($conf as $key => $vla) {
826                                 if($key == $rkey) {
827                                         unset($conf["$rkey"]);
828                                         $nconf = serialize($conf);
829                                         system("rm -rf $repostore/$key");
830                                         error_log("remove repo as $rkey");
831                                         $this->config->setConfigVar("repodata", $nconf);
832                                         $this->config->saveConfig();
833                                 }
834                         }
835                 }
836         }
837
838         function addRepo($desc, $os, $version, $arch, $other, $shorturl, $prefix, $repurl, $repotype, $init, $expiretime)
839         {
840                 $uconf = $this->config->getConfigVar("repodata");
841
842                 $cs["desc"] = $desc;
843                 $cs["os"] = $os;
844                 $cs["version"] = $version;
845                 $cs["arch"] = $arch;
846                 $cs["other"] = $other;
847                 $cs["shorturl"] = $shorturl;
848                 $cs["prefix"] = $prefix;
849                 $cs["url"] = $repurl;
850                 $cs["repotype"] = $repotype;
851                 $cs["expiretime"] = $expiretime;
852
853
854                 $ckey = 0;
855                 if($uconf !== false) {
856                         $conf = unserialize($uconf);
857                         foreach($conf as $key => $val) {
858                                 $ckey = $key;
859                         }
860                         $ckey++;
861                 }
862
863                 $conf[$ckey] = $cs;
864
865                 $nconf = serialize($conf);
866
867                 error_log("add repo as $ckey");
868                 $this->config->setConfigVar("repodata", $nconf);
869                 $this->config->saveConfig();
870
871                 // now create the base structure in the repo
872                 $repostore = $this->config->getConfigVar("storagelocation");
873
874
875                 // now call update repo
876                 if($init) $this->updateRepoYum($ckey);
877         }
878
879         function updateRepo($repokey)
880         {
881                 // we only do yum yet
882                 $this->updateRepoYum($repokey);
883         }
884
885         function updateRepoYum($repokey)
886         {
887                 $repostore = $this->config->getConfigVar("storagelocation");
888
889                 $repod = $this->getRepo($repokey);
890
891                 $repourl = $repod["url"];
892
893                 if(!file_exists("$repostore/$repokey")) {
894                         mkdir("$repostore/$repokey");
895                 }
896
897                 if(!file_exists("$repostore/$repokey/repodata")) {
898                         mkdir("$repostore/$repokey/repodata");
899                 }
900                 
901                 error_log("background yum repo update, start");
902                 global $WEB_ROOT_FS, $URL_HANDLERS, $BASE_URL;
903                 if(file_exists("$WEB_ROOT_FS/../bin/downloadfile.php")) {
904                         $scall = "/usr/bin/php $WEB_ROOT_FS/../bin/updateyumrepo.php '$repourl' '$repostore/$repokey/' > /tmp/updateyumrepo.$repokey.log 2>&1 &";
905                         system($scall);
906                 } else {
907                         error_log("cant find download yum helper... dieing");
908                 }
909                 
910
911                 //ignore_user_abort(true);
912         }
913
914         function getRepo($id)
915         {
916                 $uconf = $this->config->getConfigVar("repodata");
917                 if($uconf !== false) {
918                         $lconf = unserialize($uconf);
919                         return $lconf[$id];
920                 } else return false;
921
922         }
923
924         function getRepos()
925         {
926                 $uconf = $this->config->getConfigVar("repodata");
927                 if($uconf !== false) {
928                         return unserialize($uconf);
929                 } else return false;
930
931         }
932
933         private $config;
934 }
935
936 ?>