Rssd.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. <?php
  2. /* $Id: Rssd.php 3130 2007-06-25 23:54:26Z danez $ */
  3. /*******************************************************************************
  4. LICENSE
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License (GPL)
  7. as published by the Free Software Foundation; either version 2
  8. of the License, or (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. To read the license please visit http://www.gnu.org/copyleft/gpl.html
  14. *******************************************************************************/
  15. // states
  16. define('RSSD_STATE_NULL', 0); // null
  17. define('RSSD_STATE_OK', 1); // ok
  18. define('RSSD_STATE_ERROR', -1); // error
  19. // modes
  20. define('RSSD_MODE_CLI', 1); // cli
  21. define('RSSD_MODE_WEB', 2); // web
  22. // require SimpleHTTP
  23. require_once("inc/classes/SimpleHTTP.php");
  24. // require lastRSS
  25. require_once("inc/classes/lastRSS.php");
  26. /**
  27. * Rssd
  28. */
  29. class Rssd
  30. {
  31. // public fields
  32. var $name = "Rssd";
  33. // state
  34. var $state = RSSD_STATE_NULL;
  35. // messages-array
  36. var $messages = array();
  37. // private fields
  38. // mode
  39. var $_mode = 0;
  40. // job-vars
  41. var $_fileFilters = "";
  42. var $_fileHistory = "";
  43. var $_dirSave = "";
  44. var $_urlRSS = "";
  45. // filters
  46. var $_filters = array();
  47. // history
  48. var $_history = array();
  49. var $_historyNew = array();
  50. // data
  51. var $_data = array();
  52. // saved files
  53. var $_filesSaved = array();
  54. // lastRSS-instance
  55. var $_lastRSS;
  56. // =========================================================================
  57. // public static methods
  58. // =========================================================================
  59. /**
  60. * accessor for singleton
  61. *
  62. * @return Rssd
  63. */
  64. function getInstance() {
  65. global $instanceRssd;
  66. // initialize if needed
  67. if (!isset($instanceRssd))
  68. Rssd::initialize();
  69. return $instanceRssd;
  70. }
  71. /**
  72. * initialize Rssd.
  73. */
  74. function initialize() {
  75. global $instanceRssd;
  76. // create instance
  77. if (!isset($instanceRssd))
  78. $instanceRssd = new Rssd();
  79. }
  80. /**
  81. * getState
  82. *
  83. * @return state
  84. */
  85. function getState() {
  86. global $instanceRssd;
  87. return (isset($instanceRssd))
  88. ? $instanceRssd->state
  89. : RSSD_STATE_NULL;
  90. }
  91. /**
  92. * getMessages
  93. *
  94. * @return array
  95. */
  96. function getMessages() {
  97. global $instanceRssd;
  98. return (isset($instanceRssd))
  99. ? $instanceRssd->messages
  100. : array();
  101. }
  102. /**
  103. * process a feed
  104. *
  105. * @param $tdir
  106. * @param $filter
  107. * @param $hist
  108. * @param $url
  109. * @return boolean
  110. */
  111. function processFeed($sdir, $filter, $hist, $url) {
  112. global $instanceRssd;
  113. // initialize if needed
  114. if (!isset($instanceRssd))
  115. Rssd::initialize();
  116. // call instance-method
  117. return $instanceRssd->instance_processFeed($sdir, $filter, $hist, $url);
  118. }
  119. // =========================================================================
  120. // ctor
  121. // =========================================================================
  122. /**
  123. * do not use direct, use the factory-methods !
  124. *
  125. * @return Rssd
  126. */
  127. function Rssd() {
  128. global $argv;
  129. // cli/web
  130. $this->_mode = (empty($argv[0]))
  131. ? RSSD_MODE_WEB
  132. : RSSD_MODE_CLI;
  133. // init lastRSS-instance
  134. $this->_lastRSS = new lastRSS();
  135. $this->_lastRSS->cache_dir = '';
  136. $this->_lastRSS->stripHTML = false;
  137. }
  138. // =========================================================================
  139. // public methods
  140. // =========================================================================
  141. /**
  142. * process a feed
  143. *
  144. * @param $sdir
  145. * @param $filter
  146. * @param $hist
  147. * @param $url
  148. * @return boolean
  149. */
  150. function instance_processFeed($sdir, $filter, $hist, $url) {
  151. // (re)set state
  152. $this->state = RSSD_STATE_NULL;
  153. // validate
  154. if (!checkDirectory($sdir, 0777)) {
  155. $this->state = RSSD_STATE_ERROR;
  156. $msg = "Save-Dir ".$sdir." not valid.";
  157. array_push($this->messages , $msg);
  158. $this->_outputError($msg."\n");
  159. return false;
  160. }
  161. if (!is_file($filter)) {
  162. $this->state = RSSD_STATE_ERROR;
  163. $msg = "Filter-File ".$filter." not valid.";
  164. array_push($this->messages , $msg);
  165. $this->_outputError($msg."\n");
  166. return false;
  167. }
  168. // output
  169. $this->_outputMessage("Processing feed ".$url." ...\n");
  170. // set vars
  171. $this->_dirSave = checkDirPathString($sdir);
  172. $this->_fileFilters = $filter;
  173. $this->_fileHistory = $hist;
  174. $this->_urlRSS = $url;
  175. $this->_filters = array();
  176. $this->_history = array();
  177. $this->_historyNew = array();
  178. $this->_data = array();
  179. $this->_filesSaved = array();
  180. // load _filters
  181. if (!$this->_loadFilters())
  182. return false;
  183. // load history
  184. if (!$this->_loadHistory())
  185. return false;
  186. // load data
  187. if (!$this->_loadData())
  188. return false;
  189. // something to do ?
  190. if ($this->_data['items_count'] <= 0) { // no
  191. // state
  192. $this->state = RSSD_STATE_OK;
  193. return true;
  194. }
  195. // process data
  196. if (!$this->_processData())
  197. return false;
  198. // update history
  199. if (!$this->_updateHistory())
  200. return false;
  201. // state
  202. $this->state = RSSD_STATE_OK;
  203. // output
  204. $this->_outputMessage("feed processed. downloaded and saved ".count($this->_filesSaved)." torrents.\n");
  205. // return
  206. return true;
  207. }
  208. // =========================================================================
  209. // private methods
  210. // =========================================================================
  211. /**
  212. * load filters
  213. *
  214. * @return boolean
  215. */
  216. function _loadFilters() {
  217. $fifi = file($this->_fileFilters);
  218. $this->_filters = array_map('rtrim', $fifi);
  219. return true;
  220. }
  221. /**
  222. * load history
  223. *
  224. * @return boolean
  225. */
  226. function _loadHistory() {
  227. if (is_file($this->_fileHistory)) {
  228. $fihi = file($this->_fileHistory);
  229. $this->_history = array_map('rtrim', $fihi);
  230. } else {
  231. $this->_history = array();
  232. }
  233. return true;
  234. }
  235. /**
  236. * load data
  237. *
  238. * @return boolean
  239. */
  240. function _loadData() {
  241. $this->_data = $this->_lastRSS->Get($this->_urlRSS);
  242. if ($this->_data !== false) {
  243. return (empty($this->_data) === false);
  244. } else {
  245. $msg = "Problem getting feed-data from ".$this->_urlRSS;
  246. array_push($this->messages , $msg);
  247. $this->_outputError($msg."\n");
  248. return false;
  249. }
  250. }
  251. /**
  252. * process data
  253. *
  254. * @return boolean
  255. */
  256. function _processData() {
  257. $itemCount = count($this->_data["items"]);
  258. // filter-loop
  259. foreach ($this->_filters as $filter) {
  260. // output filtername
  261. $this->_outputMessage("***** ".$filter." *****\n");
  262. // item-loop
  263. for ($i = 0; $i < $itemCount; $i++) {
  264. // skip feed items without a link or title:
  265. if (!isset($this->_data["items"][$i]["link"]) || empty($this->_data["items"][$i]["link"]))
  266. continue;
  267. if (!isset($this->_data["items"][$i]["title"]) || empty($this->_data["items"][$i]["title"]))
  268. continue;
  269. // local vars
  270. $link = html_entity_decode($this->_data["items"][$i]["link"]);
  271. $title = $this->_data["items"][$i]["title"];
  272. // check if we have a match
  273. if (preg_match('/'.$filter.'/i', $title)) {
  274. // if not in history, process it
  275. if (!in_array($title, $this->_history)) {
  276. // output
  277. $this->_outputMessage("new match for filter '".$filter."' : ".$title."\n");
  278. // download and save
  279. if ($this->_saveTorrent($link, $title) === true) {
  280. // add to history
  281. array_push($this->_history, $title);
  282. array_push($this->_historyNew, $title);
  283. }
  284. }
  285. }
  286. }
  287. }
  288. // return
  289. return true;
  290. }
  291. /**
  292. * update history
  293. *
  294. * @return boolean
  295. */
  296. function _updateHistory() {
  297. global $cfg;
  298. if (count($this->_historyNew) > 0) {
  299. // write file
  300. $handle = false;
  301. $handle = @fopen($this->_fileHistory, "a");
  302. if (!$handle) {
  303. $this->state = RSSD_STATE_ERROR;
  304. $msg = "cannot open history ".$this->_fileHistory." for writing.";
  305. array_push($this->messages , $msg);
  306. AuditAction($cfg["constants"]["error"], "Rssd _updateHistory-Error : ".$msg);
  307. $this->_outputError($msg."\n");
  308. return false;
  309. }
  310. $result = @fwrite($handle, implode("\n", $this->_historyNew)."\n");
  311. @fclose($handle);
  312. if ($result === false) {
  313. $this->state = RSSD_STATE_ERROR;
  314. $msg = "cannot write content to history ".$this->_fileHistory.".";
  315. array_push($this->messages , $msg);
  316. AuditAction($cfg["constants"]["error"], "Rssd _updateHistory-Error : ".$msg);
  317. $this->_outputError($msg."\n");
  318. return false;
  319. }
  320. }
  321. // return
  322. return true;
  323. }
  324. /**
  325. * download and save a torrent-file
  326. *
  327. * @return boolean
  328. */
  329. function _saveTorrent($url, $title) {
  330. global $cfg;
  331. $content = SimpleHTTP::getTorrent($url);
  332. if (SimpleHTTP::getState() == SIMPLEHTTP_STATE_OK) {
  333. // filename
  334. $filename = SimpleHTTP::getFilename();
  335. if ($filename != "") {
  336. $filename = ((strpos($filename, ".torrent") !== false))
  337. ? tfb_cleanFileName($filename)
  338. : tfb_cleanFileName($filename.".torrent");
  339. }
  340. if (($filename == "") || ($filename === false) || (transferExists($filename))) {
  341. $filename = tfb_cleanFileName($title.".torrent");
  342. if (($filename === false) || (transferExists($filename))) {
  343. $filename = tfb_cleanFileName($url.".torrent");
  344. if (($filename === false) || (transferExists($filename))) {
  345. $filename = tfb_cleanFileName(md5($url.strval(@microtime())).".torrent");
  346. if (($filename === false) || (transferExists($filename))) {
  347. // Error
  348. $msg = "failed to get a valid transfer-filename for ".$url;
  349. array_push($this->messages , $msg);
  350. AuditAction($cfg["constants"]["error"], "Rssd downloadMetafile-Error : ".$msg);
  351. $this->_outputError($msg."\n");
  352. return false;
  353. }
  354. }
  355. }
  356. }
  357. // file
  358. $file = $this->_dirSave.$filename;
  359. // check if file already exists
  360. if (@is_file($file)) {
  361. // Error
  362. $msg = "the file ".$file." already exists in ".$this->_dirSave;
  363. array_push($this->messages , $msg);
  364. AuditAction($cfg["constants"]["error"], "Rssd downloadMetafile-Error : ".$msg);
  365. $this->_outputError($msg."\n");
  366. return false;
  367. }
  368. // write file
  369. $handle = false;
  370. $handle = @fopen($file, "w");
  371. if (!$handle) {
  372. $msg = "cannot open ".$file." for writing.";
  373. array_push($this->messages , $msg);
  374. AuditAction($cfg["constants"]["error"], "Rssd downloadMetafile-Error : ".$msg);
  375. $this->_outputError($msg."\n");
  376. return false;
  377. }
  378. $result = @fwrite($handle, $content);
  379. @fclose($handle);
  380. if ($result === false) {
  381. $msg = "cannot write content to ".$file.".";
  382. array_push($this->messages , $msg);
  383. AuditAction($cfg["constants"]["error"], "Rssd downloadMetafile-Error : ".$msg);
  384. $this->_outputError($msg."\n");
  385. return false;
  386. }
  387. // add to file-array
  388. array_push($this->_filesSaved, array(
  389. 'url' => $url,
  390. 'title' => $title,
  391. 'filename' => $filename,
  392. 'file' => $file
  393. )
  394. );
  395. // output
  396. $this->_outputMessage("torrent saved : \n url: ".$url."\n file: ".$file."\n");
  397. // return
  398. return true;
  399. } else {
  400. // last op was not ok
  401. $msgs = SimpleHTTP::getMessages();
  402. $this->_outputError("could not download torrent with title ".$title." from url ".$url." : \n".implode("\n", $msgs));
  403. return false;
  404. }
  405. }
  406. /**
  407. * output message
  408. *
  409. * @param $message
  410. */
  411. function _outputMessage($message) {
  412. // only in cli-mode
  413. if ($this->_mode == RSSD_MODE_CLI)
  414. printMessage($this->name, $message);
  415. }
  416. /**
  417. * output error
  418. *
  419. * @param $message
  420. */
  421. function _outputError($message) {
  422. // only in cli-mode
  423. if ($this->_mode == RSSD_MODE_CLI)
  424. printError($this->name, $message);
  425. }
  426. }
  427. ?>