We have clarified our Privacy Statement even further. Please have a look at our changes.
parse Changelog ("History") files and generate HTML pages
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

644 lines
25KB

  1. <?php
  2. #############################################################################
  3. # HistView (c) 2003-2017 by Itzchak Rehberg #
  4. # written by Itzchak Rehberg <devel AT izzysoft DOT de> #
  5. # http://www.izzysoft.de/ #
  6. # ------------------------------------------------------------------------- #
  7. # This program is free software; you can redistribute and/or modify it #
  8. # under the terms of the GNU General Public License (see doc/LICENSE) #
  9. # ------------------------------------------------------------------------- #
  10. # Download Class: Scans directories and provides download links #
  11. #############################################################################
  12. /* $Id$ */
  13. require_once(dirname(__FILE__)."/class.hvconfig.inc");
  14. /** Scanning a directory and checking for download files
  15. * @package Api
  16. * @class download
  17. * @extends hvconfig
  18. * @author Izzy (devel AT izzysoft DOT de)
  19. * @copyright (c) 2007-2017 by Itzchak Rehberg and IzzySoft
  20. * @version $Revision$ $Date$
  21. */
  22. class download extends hvconfig {
  23. var $filelist = array(); // Array[0..n] of array[name,version,sortver,file,icon[,size,date]]
  24. var $argsep = ";";
  25. var $ignored_bots = array(); // Array[0..n] of strings (substr of bot names)
  26. var $rejected_bots = array(); // Array[0..n] of strings (substr of bot names)
  27. var $crawler_nets = array(); // Array[0..n] of strings (substr of net names)
  28. var $remote_ua = "";
  29. /** Initial setup of default filetypes and date format
  30. * @constructor download
  31. * @param optional string basedir What to cut off to generate a download link.
  32. * This is usually your web servers document root. This parameter is
  33. * not needed when using the internal download method (default).
  34. * @param optional string icondir URL of the directory where the icons reside
  35. */
  36. function download($basedir="",$icondir="") {
  37. $this->hvconfig();
  38. $this->set_filetype("tar","/^([\w-\.]+)\-(\d+)\.(\d+)\.(\d+)\.tar\.gz/","tar.gz","tgz.png");
  39. $this->set_filetype("deb","/^([\w-\.]+)\_(\d+)\.(\d+)\.(\d+)\-[0-9a-z]*(\d+)_[\w]+\.deb/","deb","deb.png");
  40. $this->set_filetype("rpm","/^([\w]+)\-(\d+)\.(\d+)\.(\d+)\-[0-9a-z]*(\d+)\.[\w]+\.rpm/","rpm","rpm.png");
  41. $this->set_dateformat("d.m.Y");
  42. $this->basedir = $basedir;
  43. if (!empty($icondir)) $this->icondir = $icondir;
  44. $this->remote_ua = strtolower($_SERVER["HTTP_USER_AGENT"]);
  45. $this->set_bots("crawler",$this->crawlerfile);
  46. $this->set_bots("ignore",$this->ignorefile);
  47. $this->set_bots("reject",$this->rejectfile);
  48. if (is_array($this->db)) { // setup default db
  49. $this->db_setup($this->db["host"],$this->db["database"],$this->db["user"],$this->db["pass"],$this->db["table"],$this->db["limitTable"]);
  50. }
  51. $this->set_statisticsmode($this->statisticsmode); // make sure stats are disabled w/o database
  52. }
  53. /** Setup bots to ignore / reject
  54. * @method set_bots
  55. * @param string type "ignore" or "reject"
  56. * @param string filename file to read the bots from
  57. */
  58. function set_bots($type,$file) {
  59. if (file_exists($file)) {
  60. $bots = file($file);
  61. foreach ($bots as $bot) {
  62. $bot = trim($bot);
  63. if (empty($bot) || substr($bot,0,1)=="#") continue;
  64. switch ($type) {
  65. case "crawler" : $this->crawler_net($bot); break;
  66. case "ignore" : $this->ignore_bot($bot); break;
  67. case "reject" : $this->reject_bot($bot); break;
  68. }
  69. }
  70. }
  71. }
  72. /** Setup file types
  73. * @method set_filetype
  74. * @param string type Short name for the type, e.g. "rpm", "deb", "tar"
  75. * @param string mask Corresponding regexp mask. The back references should be
  76. * set such that <ul><li>\1 is the name of the software</li>
  77. * <li>\2.\3.\4 make up the version</li>
  78. * <li>optional \5 sets the release number (required for *.deb and *.rpm)</li></ul>
  79. * @param string extension File extension to identify this type - e.g. "deb" or "tar.gz"
  80. * @param optional string icon Complete img tag to display for this type
  81. */
  82. function set_filetype($type,$mask,$extension,$icon="") {
  83. $this->mask[$type] = $mask;
  84. $this->ext[$type] = $extension;
  85. if (empty($icon)) $this->icon[$type] = $this->deficon;
  86. else $this->icon[$type] = "<IMG SRC='".$this->icondir."/$icon' ALT='*' BORDER='0'>";
  87. }
  88. /** Set the date format to use
  89. * @method set_dateformat
  90. * @param string format Date format to use (refer to the PHP manual of date)
  91. */
  92. function set_dateformat($format) {
  93. $this->dateformat = $format;
  94. }
  95. /** Set the directory (URL) where your icons reside
  96. * @method set_icondir
  97. * @param string dir URL of the directory where the icons reside
  98. */
  99. function set_icondir($dir) {
  100. $this->icondir = $dir;
  101. }
  102. /** Setup exclude list
  103. * @method set_excludes
  104. * @param array excludes Array of files to exclude from listings
  105. * @param optional boolean replace Replace the preset list (TRUE) or append to it (FALSE)? Default is to append.
  106. */
  107. function set_excludes($excl,$replace=FALSE) {
  108. if ($replace) $this->excludes = $excl;
  109. else $this->excludes = array_merge($this->excludes,$excl);
  110. }
  111. /** Set download linktype
  112. * @method set_dllinktype
  113. * @param string type type of the link
  114. */
  115. function set_dllinktype($type) {
  116. $this->dltype = $type;
  117. }
  118. /** Set the argument separator
  119. * This is how to separate arguments in the URL. Default is ";" - you may
  120. * want to set this to "&"
  121. * @method set_argsep
  122. * @param string separator
  123. */
  124. function set_argsep($sep) {
  125. $this->argsep = $sep;
  126. }
  127. /** Set the statisticsmode
  128. * Use this to turn on (1)/Off (0) statistic functions (database related
  129. * stuff like download counters) at runtime
  130. * @method set_statisticsmode
  131. * @param integer mode 0 (to turn off stats) or 1 (to turn them on)
  132. * @return boolean success
  133. */
  134. function set_statisticsmode($mode) {
  135. $valid_modes = array(0,1);
  136. if (!is_int($mode) || !in_array($mode,$valid_modes)) {
  137. trigger_error("Invalid value '$mode' for statisticsmode ignored",E_USER_WARNING);
  138. return FALSE;
  139. }
  140. if ($mode==1 && (empty($this->dbhost)||empty($this->database)||empty($this->dbuser)||empty($this->dbtable))) {
  141. trigger_error("Cannot enable statistics mode - invalid database settings (no dbhost, database, dbuser, and/or dbtable configured)",E_USER_WARNING);
  142. $this->statisticsmode = 0;
  143. return FALSE;
  144. }
  145. $this->statisticsmode = $mode;
  146. return TRUE;
  147. }
  148. /** Setup bots to be ignored/rejected
  149. * @method protected add_bot
  150. * @param mixed bot string or array of strings (substr of botnames)
  151. * @param string cat category to add the bot to (ignore,reject)
  152. */
  153. function add_bot(&$bot,$cat) {
  154. switch ($cat) {
  155. case "ignore" :
  156. if (is_array($bot)) $this->ignored_bots = array_merge($this->ignored_bots,$bot);
  157. elseif (is_string($bot)) $this->ignored_bots[] = $bot;
  158. else trigger_error("Cannot add this bot(s) - wrong data type.",E_USER_WARNING);
  159. break;
  160. case "reject" :
  161. if (is_array($bot)) $this->rejected_bots = array_merge($this->rejected_bots,$bot);
  162. elseif (is_string($bot)) $this->rejected_bots[] = $bot;
  163. else trigger_error("Cannot add this bot(s) - wrong data type.",E_USER_WARNING);
  164. break;
  165. case "crawler" :
  166. if (is_array($bot)) $this->crawler_nets = array_merge($this->crawler_nets,$bot);
  167. elseif (is_string($bot)) $this->crawler_nets[] = $bot;
  168. else trigger_error("Cannot add this bot(s) - wrong data type.",E_USER_WARNING);
  169. break;
  170. }
  171. }
  172. /** Add bots to ignore list
  173. * @method ignore_bot
  174. * @param mixed bot string or array of strings (substr of botnames)
  175. */
  176. function ignore_bot($bot) {
  177. $this->add_bot($bot,"ignore");
  178. }
  179. /** Add bots to reject list
  180. * @method reject_bot
  181. * @param mixed bot string or array of strings (substr of botnames)
  182. */
  183. function reject_bot($bot) {
  184. $this->add_bot($bot,"reject");
  185. }
  186. /** Add name to crawler list
  187. * @method crawler_net
  188. * @param mixed name string or array of strings (substr of botnames)
  189. */
  190. function crawler_net($bot) {
  191. $this->add_bot($bot,"crawler");
  192. }
  193. /** Scan another directory
  194. * Switches to another directory. This resets the internal file array and starts over.
  195. * The filelist array will not be reset, so entries are added to it.
  196. * @method scan_dir
  197. * @param string dir Directory to scan
  198. * @param optional integer dirnum If you run multiple directories via an array, you can store the index here. Will be added to the DL URL, when internal DL method is used.
  199. */
  200. function scan_dir($dir,$dirnum="") {
  201. if (isset($this->files)) unset ($this->files);
  202. $this->dir = $dir;
  203. if(is_dir($dir)) {
  204. $thisdir = dir($dir);
  205. $version = 0; $fname = "";
  206. while($entry=$thisdir->read()) {
  207. if (!in_array($entry,$this->excludes)) $this->files[] = $entry;
  208. }
  209. }
  210. $this->interprete_filelist($dirnum);
  211. }
  212. /** Get the list of files
  213. * @method get_filenames
  214. * @return array Array[0..n] of filenames
  215. */
  216. function get_filenames() {
  217. return $this->files;
  218. }
  219. /** Get full (interpreted) filelist
  220. * @method get_filelist
  221. * @return array Array[0..n] of file arrays.
  222. * File array has the properties dir,name,version,sortver,file, icon, ilink (link with icon) and flink (link with filename).
  223. * If add_details was run before, size, date and desc are also available.
  224. */
  225. function get_filelist() {
  226. return $this->filelist;
  227. }
  228. /** Generate list of all files incl. basic information
  229. * Is called from method scan_dir
  230. * @method protected interprete_filelist
  231. * @param optional integer dirnum If you run multiple directories via an array, you can store the index here. Will be added to the DL URL, when internal DL method is used.
  232. */
  233. function interprete_filelist($dirnum="") {
  234. $i=count($this->filelist);
  235. foreach($this->files as $file) {
  236. foreach ($this->ext as $type=>$ext) {
  237. preg_match("/.*(${ext})\$/",$file,$match);
  238. if (!empty($match[1])) break;
  239. }
  240. preg_match($this->mask[$type],$file,$matches);
  241. if (!empty($matches[1]) && isset($matches[4])) {
  242. $name = $matches[1];
  243. $version = $matches[2].".".$matches[3].".".$matches[4];
  244. $sortver = $matches[2]*1000000+$matches[3]*10000+$matches[4]*100;
  245. if (isset($matches[5])) {
  246. $version .= "-".$matches[5];
  247. $sortver += $matches[5];
  248. }
  249. switch ($this->dltype) {
  250. case "internal" :
  251. $linkto = $_SERVER["PHP_SELF"]."?file=$file";
  252. if (!empty($dirnum)||$dirnum===0) $linkto .= $this->argsep."dirnum=$dirnum";
  253. break;
  254. default :
  255. $linkto = substr($this->dir,strlen($this->basedir))."/$file";
  256. break;
  257. }
  258. $ilink = "<A HREF='$linkto' REL='nofollow'>".$this->icon[$type]."</A>";
  259. $flink = "<A HREF='$linkto' REL='nofollow'>$file</A>";
  260. $this->filelist[$i] = array("dir"=>$this->dir,"name"=>$name,"type"=>$type,"version"=>$version,"sortver"=>$sortver,"file"=>$file,"icon"=>$this->icon[$type],"ilink"=>$ilink,"flink"=>$flink);
  261. ++$i;
  262. }
  263. }
  264. }
  265. /** Sort array by given key
  266. * @method protected ar_sort_by
  267. * @param array arr Array to sort
  268. * @param string orderby Field to order by
  269. * @param optional boolean rev Reverse order (default:false)
  270. * @param optional integer method One of the constants SORT_REGULAR,
  271. * SORT_NUMERIC, SORT_STRING, SORT_LOCALE_STRING
  272. */
  273. function ar_sort_by($arr, $orderby, $reverse=false, $flags=SORT_REGULAR) {
  274. // Create 1-dimensional named array with just sortfield (in stead of record) values
  275. $named_hash = array();
  276. foreach($arr as $key=>$fields)
  277. $named_hash["$key"] = $fields[$orderby];
  278. // Order 1-dimensional array, maintaining key-value relations
  279. if($reverse) $rc = arsort($named_hash,$flags) ;
  280. else $rc = asort($named_hash, $flags);
  281. if ($rc) $ok = "OK"; else $ok = "Failure!";
  282. // Create copy of named records array in order of sortarray
  283. $sorted_records = array();
  284. foreach($named_hash as $key=>$val)
  285. $sorted_records["$key"]= $arr[$key];
  286. return array_merge($sorted_records); // named_recs_sort()
  287. }
  288. /** Sort filelist by version
  289. * @method sort_by_version
  290. * @param optional boolean rev Reverse order? Default: False
  291. */
  292. function sort_by_version($rev=FALSE) {
  293. $this->filelist = $this->ar_sort_by($this->filelist,"sortver",$rev,SORT_NUMERIC);
  294. }
  295. /** Sort by filename
  296. * @method sort_by_filename
  297. * @param optional boolean rev Reverse order? Default: False
  298. */
  299. function sort_by_filename($rev=FALSE) {
  300. $this->filelist = $this->ar_sort_by($this->filelist,"file",$rev);
  301. }
  302. /** Add details to the filelist (fields "size" and "date")
  303. * @method add_details
  304. * @param optional string descdir Directory where the description files reside.
  305. * Name of a description file must be either &lt;name&gt;.desc (for a
  306. * general, version independent description) or
  307. * &lt;name&gt;_&lt;version&gt;.desc (description bound to a specific
  308. * version). The latter one is used (if found), the first one otherwise
  309. * (if found). Descriptions will be preceded by "&lt;name&gt; v&lt;version&gt;".
  310. * If a description file is found, it then will be added after an additional
  311. * line break (&lt;BR&gt;).
  312. * @param optional boolean descreplace Replace the short desc (TRUE, default)
  313. * or append to it (FALSE)
  314. */
  315. function add_details($descdir="",$descreplace=TRUE) {
  316. $fc = count($this->filelist);
  317. for ($i=0;$i<$fc;++$i) {
  318. $fname = $this->filelist[$i]["dir"]."/".$this->filelist[$i]["file"];
  319. $size = filesize($fname);
  320. if ($size>1048576) { // MB
  321. $size = sprintf("%01.1f",round($size/1048576,1))." MB";
  322. } elseif ($size>1024) { // kB
  323. $size = sprintf("%01.1f",round($size/1024,1))." kB";
  324. } else { // B
  325. $size .= " B";
  326. }
  327. $this->filelist[$i]["size"] = $size;
  328. $this->filelist[$i]["date"] = date($this->dateformat,filemtime($fname));
  329. $this->filelist[$i]["desc"] = $this->filelist[$i]["name"]." v".$this->filelist[$i]["version"];
  330. if (!empty($descdir)) {
  331. $basename = $descdir."/".$this->filelist[$i]["name"];
  332. if (file_exists($basename."_".$this->filelist[$i]["version"].".desc")) $dfile = $basename."_".$this->filelist[$i]["version"].".desc";
  333. elseif (file_exists($basename.".desc")) $dfile = $basename.".desc";
  334. else continue;
  335. if ($descreplace)
  336. $this->filelist[$i]["desc"] = file_get_contents($dfile);
  337. else
  338. $this->filelist[$i]["desc"] .= "<BR>".file_get_contents($dfile);
  339. }
  340. }
  341. }
  342. /** Reject a client and quit
  343. * @method reject
  344. */
  345. function reject() {
  346. header($this->rejectheader);
  347. echo $this->rejectmsg;
  348. exit;
  349. }
  350. /** Handle IP blacklist
  351. * @method blacklistCheck
  352. */
  353. function blacklistCheck() {
  354. if ( $this->blacklistAction != 'deny' || !file_exists($this->blacklistfile) ) return;
  355. static $blacklist;
  356. if (empty($blacklist)) $blacklist = file_get_contents($this->blacklistfile);
  357. if ( preg_match('|^'.$_SERVER['REMOTE_ADDR'].'$|m',$blacklist) ) $this->reject();
  358. }
  359. /** Handle request w/o referer
  360. * @method refererCheck
  361. */
  362. function refererCheck() {
  363. if (!empty($_SERVER['HTTP_REFERER'])) return;
  364. switch ($this->noRefererAction) { // pass, deny, whois
  365. case "deny" : $this->reject(); break;
  366. case "whois": if ($this->is_crawler_net()) $this->reject(); break;
  367. case "pass" :
  368. default : break;
  369. }
  370. }
  371. /** Query the whois database
  372. * @method whois
  373. * @param string host IP/hostname
  374. * @param optional boolean raw whether to include the raw whois information (default: FALSE)
  375. * @param optional string server whois server to use (default: "whois.arin.net")
  376. * @param optional integer port (default: 43)
  377. * @return array whois
  378. */
  379. function whois($host,$raw=FALSE,$server="whois.arin.net",$port=43) {
  380. if (empty($host)) return false;
  381. $fp=@fsockopen($server,$port);
  382. if(!$fp) {
  383. trigger_error("Could not establish connection to whois server $server:43",E_USER_NOTICE);
  384. return false;
  385. }
  386. fputs($fp,"$host\r\n");
  387. $resp = '';
  388. while(!feof($fp)) $resp .= fgets($fp,256);
  389. fclose($fp);
  390. $arr = explode("\n",$resp);
  391. foreach ($arr as $item) {
  392. $item = trim($item);
  393. if ( empty($item) || substr($item,0,1)=='%' || substr($item,0,1)=='#') continue;
  394. $pair = explode(':',$item);
  395. if (count($pair)>2) for ($i=2;$i<count($pair);++$i) $pair[1].=':'.$pair[$i];
  396. if (isset($pair[1])) switch(trim($pair[0])) {
  397. case "remarks":
  398. case "source" :
  399. case "tech-c" :
  400. case "admin-c":
  401. case "mnt-ref":
  402. case "mnt-by" :
  403. case "address":
  404. case "e-mail" : $whois[trim($pair[0])][] = trim($pair[1]); break;
  405. default : $whois[trim($pair[0])] = trim($pair[1]); break;
  406. }
  407. if ($raw) $whois["raw"] = $resp;
  408. }
  409. if (!empty($whois["ReferralServer"])) {
  410. $refServer = $whois["ReferralServer"];
  411. if (substr($refServer,0,8)=='whois://') $refServer = substr($refServer,8);
  412. elseif (substr($refServer,0,9)=='rwhois://') $refServer = substr($refServer,9);
  413. if ( preg_match('|^(.*)\:(\d+)/{0,1}$|',$refServer,$match) ) {
  414. $port = $match[2]; $refServer = $match[1];
  415. } else $port = 43;
  416. if ($server=="whois.arin.net") {
  417. $who = $this->whois($host,$raw,$refServer,$port);
  418. if (count($who)<3) $whois = array_merge($whois,$who);
  419. else $whois = $who;
  420. }
  421. }
  422. return $whois;
  423. }
  424. /** Network check (where does the request come from)
  425. * @method is_crawler_net
  426. * @return boolean
  427. */
  428. function is_crawler_net() {
  429. $whois = $this->whois($_SERVER['REMOTE_ADDR']);
  430. if (isset($whois['netname'])) $netname = strtolower($whois['netname']); else $netname = '§§§';
  431. if (isset($whois['OrgName'])) $orgname = strtolower($whois['OrgName']); else $orgname = '§§§';
  432. if (isset($whois['OrgNOCName'])) $orgNocName = strtolower($whois['OrgNOCName']); else $orgNocName = '§§§';
  433. if (isset($whois['descr'])) $desc = strtolower($whois['descr']); else $desc = '§§§';
  434. foreach ($this->crawler_nets as $bot) {
  435. if (strpos($netname,$bot)!==FALSE) return TRUE;
  436. if (strpos($desc,$bot)!==FALSE) return TRUE;
  437. if (strpos($orgname,$bot)!==FALSE) return TRUE;
  438. if (strpos($orgNocName,$bot)!==FALSE) return TRUE;
  439. }
  440. return FALSE;
  441. }
  442. /** Get the prog name from the file name
  443. * @method protected getProgName
  444. * @param string file name of the file
  445. * @return string prog name of the prog
  446. */
  447. function getProgname($file) {
  448. foreach ($this->ext as $type=>$ext) {
  449. preg_match("/.*(${ext})\$/",$file,$match);
  450. if (!empty($match[1])) break;
  451. }
  452. preg_match($this->mask[$type],$file,$matches);
  453. $prog = $matches[1];
  454. if ( empty($prog) ) $prog = $file;
  455. if ( empty($this->map_names[$prog]) ) return $prog;
  456. return $this->map_names[$prog];
  457. }
  458. /** Check for download limits and reject the request if they are exceeded
  459. * @method limit_check
  460. * @param string file name of the downloaded file
  461. */
  462. function limit_check($file) {
  463. if (!$this->dlFileLimit) return; // Limits are disabled
  464. if ( $this->dlLimitAutopurge ) $this->limit_purge();
  465. $prog = $this->getProgname($file);
  466. $db = $this->db_init();
  467. $query = "INSERT INTO ".$this->dbLimitTable." (dl_date,prog,remote_addr,http_user_agent)"
  468. . " VALUES (SYSDATE(),'$prog','".$_SERVER["REMOTE_ADDR"]."','".$_SERVER["HTTP_USER_AGENT"]."')";
  469. if (!@$db->query($query)) {
  470. trigger_error("Failed to update the database: ".$db->Error." (".$db->Errno.")",E_USER_WARNING);
  471. return;
  472. }
  473. $query = "SELECT COUNT(dl_date) AS num FROM " . $this->dbLimitTable
  474. . " WHERE remote_addr='".$_SERVER["REMOTE_ADDR"]."'"
  475. . " AND prog='$prog'"
  476. . " AND dl_date > SYSDATE() - INTERVAL ".$this->dlTimeLimit." SECOND";
  477. $db->query($query);
  478. $db->next_record();
  479. if ( $db->f('num') > $this->dlFileLimit ) $this->reject();
  480. }
  481. /** Purge the limits table
  482. * @method limit_purge
  483. */
  484. function limit_purge() {
  485. $db = $this->db_init();
  486. $query = "DELETE FROM ".$this->dbLimitTable." WHERE dl_date < SYSDATE() - INTERVAL ".$this->dlTimeLimit." SECOND";
  487. if (!$db->query($query)) {
  488. trigger_error("Failed to update the database: ".$db->Error." (".$db->Errno.")",E_USER_NOTICE);
  489. return;
  490. }
  491. }
  492. /** Download a file (if the remote UA is not in the reject list)
  493. * @method sendfile
  494. * @param string filename File to download
  495. * @param optional string directory Directory where the file resides (if other than the recent one)
  496. * @return boolean file_sent TRUE if file found, FALSE otherwise
  497. */
  498. function sendfile($fname,$dir="") {
  499. foreach ($this->rejected_bots as $ua) {
  500. if (strpos($this->remote_ua,strtolower($ua))!==FALSE) $this->reject(); // kick off bots
  501. }
  502. $this->blacklistCheck();
  503. $this->refererCheck();
  504. if (empty($dir) && isset($this->dir)) $dir = $this->dir;
  505. $file = $dir."/".$fname;
  506. if (!file_exists($file)) return FALSE;
  507. $this->limit_check($fname);
  508. if ($fd = fopen ($file,"rb")) {
  509. $this->dbcounter($fname);
  510. $fsize = filesize($file);
  511. header("Content-type: application/octet-stream");
  512. header("Content-Disposition: attachment; filename=\"".$fname."\"");
  513. header("Content-length: $fsize");
  514. fpassthru($fd);
  515. fclose($fd);
  516. return TRUE;
  517. }
  518. }
  519. /** Increase download counter in the database (if statisticsmode is enabled
  520. * and the Remote UA is not in the ignore list)
  521. * @method dbcounter
  522. * @param string filename Filename to process
  523. */
  524. function dbcounter($file) {
  525. if ($this->statisticsmode==0 || !isset($this->dbuser)) return;
  526. $date = date('Y-m-d');
  527. foreach ($this->ignored_bots as $ua) {
  528. if (strpos($this->remote_ua,strtolower($ua))!==FALSE) { // do not count bot downloads
  529. return;
  530. }
  531. }
  532. $name = $this->getProgname($file);
  533. if (!empty($name)) {
  534. foreach ($this->ext as $type=>$ext) {
  535. preg_match("/.*(${ext})\$/",$file,$match);
  536. if (!empty($match[1])) break;
  537. }
  538. preg_match($this->mask[$type],$file,$matches);
  539. $date = date('Y-m-d');
  540. $version = $matches[2].".".$matches[3].".".$matches[4];
  541. if ( isset($_SERVER['HTTP_REFERER']) ) $referer = $_SERVER['HTTP_REFERER']; else $referer = '';
  542. $query = "INSERT INTO ".$this->dbtable." (dl_date,prog,newver,referrer,remote_addr,http_user_agent)"
  543. . " VALUES ('$date','$name','$version','$referer','".$_SERVER["REMOTE_ADDR"]."','".$_SERVER["HTTP_USER_AGENT"]."')";
  544. $db = $this->db_init();
  545. @$db->query($query) || trigger_error("Failed to update the database: ".$db->Error." (".$db->Errno.")",E_USER_WARNING);
  546. }
  547. }
  548. /** Setup database connection
  549. * @method db_setup
  550. * @param string host hostname the DB is running on
  551. * @param string database Name of the database to use
  552. * @param string user DB User to connect with
  553. * @param string passwd Password to use
  554. * @param string table Name of the download table
  555. * @param string limitTable Name of the download limits table
  556. */
  557. function db_setup($host,$db,$user,$pass,$table,$limitTable='hvlimits') {
  558. $this->dbhost = $host;
  559. $this->database = $db;
  560. $this->dbuser = $user;
  561. $this->dbpass = $pass;
  562. $this->dbtable = $table;
  563. $this->dbLimitTable = $limitTable;
  564. }
  565. /** Initialize DB and hand-out a handle to it
  566. * @method protected db_init
  567. * @return ref object db handle to the database class
  568. */
  569. function &db_init() {
  570. static $db;
  571. if ( !isset($db->User) ) {
  572. require_once ( "class.db_mysql.inc" );
  573. $db = new db_mysql;
  574. $db->Host = $this->dbhost;
  575. $db->Database = $this->database;
  576. $db->User = $this->dbuser;
  577. $db->Password = $this->dbpass;
  578. $db->Halt_On_Error = "no";
  579. }
  580. return $db;
  581. }
  582. /** Send latest version
  583. * @method send_latest
  584. * @param string prog Which program is requested
  585. * @param string type What type of archive (first parameter of set_filetype)
  586. * @param optional string directory Directory where the file resides (if it was not scanned yet)
  587. * @return boolean file_send Whether we found something to send.
  588. */
  589. function send_latest($prog,$type,$dir) {
  590. if (!empty($dir)) $this->scan_dir($dir);
  591. $fc = count($this->filelist);
  592. $list = array();
  593. for ($i=0;$i<$fc;++$i) {
  594. if ($this->filelist[$i]["name"] != $prog) continue;
  595. if ($this->filelist[$i]["type"] != $type) continue;
  596. $list[$i] = $this->filelist[$i];
  597. }
  598. if (empty($list)) return FALSE;
  599. $list = $this->ar_sort_by($list,"sortver");
  600. $list = array_merge($list); // re-arrange keys
  601. $fc = count($list);
  602. if (!$this->sendfile($list[$fc-1]["file"],$dir)) return FALSE;
  603. return TRUE;
  604. }
  605. } // class download
  606. ?>