management.class.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867
  1. <?php
  2. /**
  3. * Insipid
  4. * Personal web-bookmark-system
  5. *
  6. * Copyright 2016-2020 Johannes Keßler
  7. *
  8. * Development starting from 2011: Johannes Keßler
  9. * https://www.bananas-playground.net/projekt/insipid/
  10. *
  11. * creator:
  12. * Luke Reeves <luke@neuro-tech.net>
  13. *
  14. * This program is free software: you can redistribute it and/or modify
  15. * it under the terms of the GNU General Public License as published by
  16. * the Free Software Foundation, either version 3 of the License, or
  17. * (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program. If not, see http://www.gnu.org/licenses/gpl-3.0.
  26. *
  27. */
  28. class Management {
  29. const LINK_QUERY_STATUS = 2;
  30. const COMBINED_SELECT_VALUES = "any_value(`id`) as id,
  31. any_value(`link`) as link,
  32. any_value(`created`) as created,
  33. any_value(`status`) as `status`,
  34. any_value(`description`) as description,
  35. any_value(`title`) as title,
  36. any_value(`image`) as image,
  37. any_value(`hash`) as hash,
  38. any_value(`tag`) as tag,
  39. any_value(`category`) as category,
  40. any_value(`categoryId`) as categoryId,
  41. any_value(`tagId`) as tagId";
  42. /**
  43. * the database object
  44. * @var object
  45. */
  46. private $DB;
  47. /**
  48. * Type of links based on status to show
  49. * @var bool
  50. */
  51. private $_queryStatus = self::LINK_QUERY_STATUS;
  52. public function __construct($databaseConnectionObject) {
  53. $this->DB = $databaseConnectionObject;
  54. }
  55. /**
  56. * Show private links or not
  57. * @param $bool
  58. */
  59. public function setShowPrivate($bool) {
  60. $this->_queryStatus = self::LINK_QUERY_STATUS;
  61. if($bool === true) {
  62. $this->_queryStatus = 1;
  63. }
  64. }
  65. /**
  66. * Show awaiting moderation links or not
  67. * @param $bool
  68. */
  69. public function setShowAwm($bool) {
  70. $this->_queryStatus = self::LINK_QUERY_STATUS;
  71. if($bool === true) {
  72. $this->_queryStatus = 3;
  73. }
  74. }
  75. /**
  76. * get all the available categories from the DB.
  77. * optional limit
  78. * optional stats
  79. * @param bool | int $limit
  80. * @param bool $stats
  81. * @return array
  82. */
  83. public function categories($limit=false, $stats=false) {
  84. $ret = array();
  85. $statsInfo = array();
  86. if($stats === true) {
  87. $queryStr = "SELECT
  88. COUNT(*) AS amount,
  89. any_value(cr.categoryid) AS categoryId
  90. FROM `".DB_PREFIX."_categoryrelation` AS cr, `".DB_PREFIX."_link` AS t
  91. WHERE cr.linkid = t.id";
  92. $queryStr .= " AND ".$this->_decideLinkTypeForQuery();
  93. $queryStr .= " GROUP BY categoryid";
  94. $query = $this->DB->query($queryStr);
  95. if(!empty($query)) {
  96. while($result = $query->fetch_assoc()) {
  97. $statsInfo[$result['categoryId']] = $result['amount'];
  98. }
  99. }
  100. }
  101. $queryStr = "SELECT
  102. any_value(`id`) as id,
  103. any_value(`name`) as name
  104. FROM `".DB_PREFIX."_category`
  105. ORDER BY `name` ASC";
  106. if(!empty($limit)) {
  107. $queryStr .= " LIMIT $limit";
  108. }
  109. $query = $this->DB->query($queryStr);
  110. if(!empty($query)) {
  111. while($result = $query->fetch_assoc()) {
  112. if($stats === true && isset($statsInfo[$result['id']])) {
  113. $ret[$result['id']] = array('name' => $result['name'], 'amount' => $statsInfo[$result['id']]);
  114. }
  115. else {
  116. $ret[$result['id']] = array('name' => $result['name'], 'amount' => 0);
  117. }
  118. }
  119. }
  120. return $ret;
  121. }
  122. /**
  123. * get all the available tags from the DB.
  124. * optional limit
  125. * optional stats
  126. * @param bool | int $limit
  127. * @param bool $stats
  128. * @return array
  129. */
  130. public function tags($limit=false, $stats=false) {
  131. $ret = array();
  132. $statsInfo = array();
  133. if($stats === true) {
  134. $queryStr = "SELECT
  135. COUNT(*) AS amount,
  136. any_value(tr.tagid) AS tagId
  137. FROM `".DB_PREFIX."_tagrelation` AS tr, `".DB_PREFIX."_link` AS t
  138. WHERE tr.linkid = t.id";
  139. $queryStr .= " AND ".$this->_decideLinkTypeForQuery();
  140. $queryStr .= " GROUP BY tagId";
  141. $query = $this->DB->query($queryStr);
  142. if(!empty($query)) {
  143. while($result = $query->fetch_assoc()) {
  144. $statsInfo[$result['tagId']] = $result['amount'];
  145. }
  146. }
  147. }
  148. $queryStr = "SELECT
  149. any_value(`id`) as id,
  150. any_value(`name`) as name
  151. FROM `".DB_PREFIX."_tag`
  152. ORDER BY `name` ASC";
  153. if(!empty($limit)) {
  154. $queryStr .= " LIMIT $limit";
  155. }
  156. $query = $this->DB->query($queryStr);
  157. if(!empty($query)) {
  158. while($result = $query->fetch_assoc()) {
  159. if($stats === true && isset($statsInfo[$result['id']])) {
  160. $ret[$result['id']] = array('name' => $result['name'], 'amount' => $statsInfo[$result['id']]);
  161. }
  162. else {
  163. $ret[$result['id']] = array('name' => $result['name'], 'amount' => 0);
  164. }
  165. }
  166. }
  167. return $ret;
  168. }
  169. /**
  170. * return the latest added links
  171. * @param int $limit
  172. * @return array
  173. */
  174. public function latestLinks($limit=5) {
  175. $ret = array();
  176. $queryStr = "SELECT `title`, `link` FROM `".DB_PREFIX."_link` AS t";
  177. $queryStr .= " WHERE ".$this->_decideLinkTypeForQuery();
  178. $queryStr .= " ORDER BY `created` DESC";
  179. if(!empty($limit)) {
  180. $queryStr .= " LIMIT $limit";
  181. }
  182. $query = $this->DB->query($queryStr);
  183. if(!empty($query) && $query->num_rows > 0) {
  184. $ret = $query->fetch_all(MYSQLI_ASSOC);
  185. }
  186. return $ret;
  187. }
  188. /**
  189. * get all the categories ordered by link added date
  190. */
  191. public function categoriesByDateAdded() {
  192. $ret = array();
  193. $categories = $this->categories();
  194. foreach($categories as $k=>$v) {
  195. $latestLink = $this->latestLinkForCategory($k);
  196. if(!empty($latestLink)) {
  197. array_push($ret, array('created' => $latestLink[0]['created'], 'id' => $k, 'name' => $v['name']));
  198. }
  199. }
  200. $_created = array_column($ret, 'created');
  201. array_multisort($_created, SORT_DESC, $ret);
  202. return $ret;
  203. }
  204. /**
  205. * find all links by given category string or id.
  206. * Return array sorted by creation date DESC
  207. * @param int $id Category ID
  208. * @param string $string Category as string
  209. * @param array $options Array with limit|offset|sort|sortDirection
  210. * @return array
  211. */
  212. public function linksByCategory($id, $string, $options=array()) {
  213. $ret = array();
  214. if(!isset($options['limit'])) $options['limit'] = 5;
  215. if(!isset($options['offset'])) $options['offset'] = false;
  216. if(!isset($options['sort'])) $options['sort'] = false;
  217. if(!isset($options['sortDirection'])) $options['sortDirection'] = false;
  218. $querySelect = "SELECT ".self::COMBINED_SELECT_VALUES;
  219. $queryFrom = " FROM `".DB_PREFIX."_combined` AS t";
  220. $queryWhere = " WHERE ".$this->_decideLinkTypeForQuery();
  221. if(!empty($id) && is_numeric($id)) {
  222. $queryWhere .= " AND t.categoryId = '" . $this->DB->real_escape_string($id) . "'";
  223. }
  224. elseif(!empty($string) && is_string($string)) {
  225. $queryWhere .= " AND t.category = '" . $this->DB->real_escape_string($string) . "'";
  226. }
  227. else {
  228. return $ret;
  229. }
  230. $queryGroup = " GROUP BY t.hash";
  231. $queryOrder = " ORDER BY";
  232. if(!empty($options['sort'])) {
  233. $queryOrder .= ' t.'.$options['sort'];
  234. }
  235. else {
  236. $queryOrder .= " t.created";
  237. }
  238. if(!empty($options['sortDirection'])) {
  239. $queryOrder .= ' '.$options['sortDirection'];
  240. }
  241. else {
  242. $queryOrder .= " DESC";
  243. }
  244. $queryLimit = '';
  245. # this allows the set the limit to false
  246. if(!empty($options['limit'])) {
  247. $queryLimit .= " LIMIT ".$options['limit'];
  248. # offset can be 0
  249. if($options['offset'] !== false) {
  250. $queryLimit .= " OFFSET ".$options['offset'];
  251. }
  252. }
  253. $query = $this->DB->query($querySelect.$queryFrom.$queryWhere.$queryGroup.$queryOrder.$queryLimit);
  254. if(!empty($query) && $query->num_rows > 0) {
  255. while($result = $query->fetch_assoc()) {
  256. $linkObj = new Link($this->DB);
  257. $ret['results'][] = $linkObj->loadShortInfo($result['hash']);
  258. unset($linkObj);
  259. }
  260. $query = $this->DB->query("SELECT COUNT(DISTINCT(t.hash)) AS amount ".$queryFrom.$queryWhere);
  261. $result = $query->fetch_assoc();
  262. $ret['amount'] = $result['amount'];
  263. }
  264. return $ret;
  265. }
  266. /**
  267. * find all links by given tag string or id.
  268. * Return array sorted by creation date DESC
  269. * @param int $id Tag id
  270. * @param string $string Tag as string
  271. * @param array $options Array with limit|offset|sort|sortDirection
  272. * @return array
  273. */
  274. public function linksByTag($id, $string, $options=array()) {
  275. $ret = array();
  276. if(!isset($options['limit'])) $options['limit'] = 5;
  277. if(!isset($options['offset'])) $options['offset'] = false;
  278. if(!isset($options['sort'])) $options['sort'] = false;
  279. if(!isset($options['sortDirection'])) $options['sortDirection'] = false;
  280. $querySelect = "SELECT ".self::COMBINED_SELECT_VALUES;
  281. $queryFrom = " FROM `".DB_PREFIX."_combined` AS t";
  282. $queryWhere = " WHERE ".$this->_decideLinkTypeForQuery();
  283. if(!empty($id) && is_numeric($id)) {
  284. $queryWhere .= " AND t.tagId = '" . $this->DB->real_escape_string($id) . "'";
  285. }
  286. elseif(!empty($string) && is_string($string)) {
  287. $queryWhere .= " AND t.tag = '" . $this->DB->real_escape_string($string) . "'";
  288. }
  289. else {
  290. return $ret;
  291. }
  292. $queryGroup = " GROUP BY t.hash";
  293. $queryOrder = " ORDER BY";
  294. if(!empty($options['sort'])) {
  295. $queryOrder .= ' t.'.$options['sort'];
  296. }
  297. else {
  298. $queryOrder .= " t.created";
  299. }
  300. if(!empty($options['sortDirection'])) {
  301. $queryOrder .= ' '.$options['sortDirection'];
  302. }
  303. else {
  304. $queryOrder .= " DESC";
  305. }
  306. $queryLimit = '';
  307. # this allows the set the limit to false
  308. if(!empty($options['limit'])) {
  309. $queryLimit .= " LIMIT ".$options['limit'];
  310. # offset can be 0
  311. if($options['offset'] !== false) {
  312. $queryLimit .= " OFFSET ".$options['offset'];
  313. }
  314. }
  315. $query = $this->DB->query($querySelect.$queryFrom.$queryWhere.$queryGroup.$queryOrder.$queryLimit);
  316. if(!empty($query) && $query->num_rows > 0) {
  317. while($result = $query->fetch_assoc()) {
  318. $linkObj = new Link($this->DB);
  319. $ret['results'][] = $linkObj->loadShortInfo($result['hash']);
  320. unset($linkObj);
  321. }
  322. $query = $this->DB->query("SELECT COUNT(DISTINCT(t.hash)) AS amount ".$queryFrom.$queryWhere);
  323. $result = $query->fetch_assoc();
  324. $ret['amount'] = $result['amount'];
  325. }
  326. return $ret;
  327. }
  328. /**
  329. * return all links and Info we have from the combined view
  330. * @param bool | int $limit
  331. * @param bool $offset
  332. * @return array
  333. */
  334. public function links($limit=10,$offset=false) {
  335. $ret = array();
  336. $querySelect = "SELECT `hash`";
  337. $queryFrom = " FROM `".DB_PREFIX."_link` AS t";
  338. $queryWhere = " WHERE ".$this->_decideLinkTypeForQuery();
  339. $queryOrder = " ORDER BY `created` DESC";
  340. $queryLimit = "";
  341. if(!empty($limit)) {
  342. $queryLimit = " LIMIT $limit";
  343. if($offset !== false) {
  344. $queryLimit .= " OFFSET $offset";
  345. }
  346. }
  347. $query = $this->DB->query($querySelect.$queryFrom.$queryWhere.$queryOrder.$queryLimit);
  348. if(!empty($query) && $query->num_rows > 0) {
  349. while($result = $query->fetch_assoc()) {
  350. $linkObj = new Link($this->DB);
  351. $ret['results'][] = $linkObj->loadShortInfo($result['hash']);
  352. unset($linkObj);
  353. }
  354. $query = $this->DB->query("SELECT COUNT(t.hash) AS amount ".$queryFrom.$queryWhere);
  355. $result = $query->fetch_assoc();
  356. $ret['amount'] = $result['amount'];
  357. }
  358. return $ret;
  359. }
  360. /**
  361. * return the latest added link for given category id
  362. * @param int $categoryid
  363. * @return array
  364. */
  365. public function latestLinkForCategory($categoryid) {
  366. $ret = array();
  367. if(!empty($categoryid) && is_numeric($categoryid)) {
  368. $queryStr = "SELECT ".self::COMBINED_SELECT_VALUES."
  369. FROM `".DB_PREFIX."_combined` AS t";
  370. $queryStr .= " WHERE ".$this->_decideLinkTypeForQuery();
  371. $queryStr .= " AND t.categoryId = '" . $this->DB->real_escape_string($categoryid) . "'
  372. ORDER BY t.created DESC
  373. LIMIT 1";
  374. $query = $this->DB->query($queryStr);
  375. if(!empty($query) && $query->num_rows > 0) {
  376. $ret = $query->fetch_all(MYSQLI_ASSOC);
  377. }
  378. }
  379. return $ret;
  380. }
  381. /**
  382. * Search for the given url in the links table
  383. * @param $url
  384. * @return mixed
  385. */
  386. public function searchForLinkByURL($url) {
  387. $ret = false;
  388. if(!empty($url)) {
  389. $queryStr = "SELECT * FROM `".DB_PREFIX."_link` AS t";
  390. $queryStr .= " WHERE ".$this->_decideLinkTypeForQuery();
  391. $queryStr .= " AND t.link = '".$this->DB->real_escape_string($url)."'";
  392. $query = $this->DB->query($queryStr);
  393. if(!empty($query) && $query->num_rows > 0) {
  394. $ret = $query->fetch_all(MYSQLI_ASSOC);
  395. }
  396. }
  397. return $ret;
  398. }
  399. /**
  400. * search for given searchstring in the search data of the links
  401. * @param $searchStr
  402. * @return mixed
  403. */
  404. public function searchForLinkBySearchData($searchStr) {
  405. $ret = false;
  406. if(!empty($searchStr)) {
  407. $queryStr = "SELECT *,
  408. MATCH (`search`) AGAINST ('".$this->DB->real_escape_string($searchStr)."' IN BOOLEAN MODE) AS score
  409. FROM `".DB_PREFIX."_link` AS t
  410. WHERE MATCH (`search`) AGAINST ('".$this->DB->real_escape_string($searchStr)."' IN BOOLEAN MODE)";
  411. $queryStr .= " AND ".$this->_decideLinkTypeForQuery();
  412. $queryStr .= " ORDER BY score DESC";
  413. $query = $this->DB->query($queryStr);
  414. if(!empty($query) && $query->num_rows > 0) {
  415. $ret = $query->fetch_all(MYSQLI_ASSOC);
  416. }
  417. }
  418. return $ret;
  419. }
  420. /**
  421. * amount of links in the DB. Status 1 and 2 only
  422. * @return int
  423. */
  424. public function linkAmount() {
  425. $ret = 0;
  426. $queryStr = "SELECT COUNT(*) AS amount
  427. FROM `".DB_PREFIX."_link` AS t";
  428. $queryStr .= " WHERE ".$this->_decideLinkTypeForQuery();
  429. $query = $this->DB->query($queryStr);
  430. if(!empty($query) && $query->num_rows > 0) {
  431. $result = $query->fetch_assoc();
  432. $ret = $result['amount'];
  433. }
  434. return $ret;
  435. }
  436. /**
  437. * amount of tags
  438. * @return int
  439. */
  440. public function tagAmount() {
  441. $ret = 0;
  442. $queryStr = "SELECT COUNT(*) AS amount FROM `".DB_PREFIX."_tag`";
  443. $query = $this->DB->query($queryStr);
  444. if(!empty($query) && $query->num_rows > 0) {
  445. $result = $query->fetch_assoc();
  446. $ret = $result['amount'];
  447. }
  448. return $ret;
  449. }
  450. /**
  451. * amount of categories
  452. * @return int
  453. */
  454. public function categoryAmount() {
  455. $ret = 0;
  456. $queryStr = "SELECT COUNT(*) AS amount FROM `".DB_PREFIX."_category`";
  457. $query = $this->DB->query($queryStr);
  458. if(!empty($query) && $query->num_rows > 0) {
  459. $result = $query->fetch_assoc();
  460. $ret = $result['amount'];
  461. }
  462. return $ret;
  463. }
  464. /**
  465. * Amount of links need moderation
  466. * @return int
  467. */
  468. public function moderationAmount() {
  469. $ret = 0;
  470. $queryStr = "SELECT COUNT(*) AS amount FROM `".DB_PREFIX."_link`";
  471. $queryStr .= " WHERE `status` = 3";
  472. $query = $this->DB->query($queryStr);
  473. if(!empty($query) && $query->num_rows > 0) {
  474. $result = $query->fetch_assoc();
  475. $ret = $result['amount'];
  476. }
  477. return $ret;
  478. }
  479. /**
  480. * get the used disk space for local image storage
  481. * @return false|int
  482. */
  483. public function storageAmount() {
  484. $ret = 0;
  485. $_storageFolder = ABSOLUTE_PATH.'/'.LOCAL_STORAGE;
  486. if(file_exists($_storageFolder) && is_readable($_storageFolder)) {
  487. $ret = Summoner::folderSize($_storageFolder);
  488. }
  489. return $ret;
  490. }
  491. /**
  492. * empties the local storage directory
  493. * @return bool
  494. */
  495. public function clearLocalStorage() {
  496. $ret = false;
  497. $_storageFolder = ABSOLUTE_PATH.'/'.LOCAL_STORAGE;
  498. if(file_exists($_storageFolder) && is_writable($_storageFolder)) {
  499. $ret = Summoner::recursive_remove_directory($_storageFolder,true);
  500. }
  501. return $ret;
  502. }
  503. /**
  504. * Load link by given hash. Do not use Link class directly.
  505. * Otherwise the authentication will be ignored.
  506. * @param String $hash Link hash
  507. * @param bool $fullInfo Load all the info we have
  508. * @param bool $withObject An array with data and the link obj itself
  509. * @return array|mixed
  510. */
  511. public function loadLink($hash,$fullInfo=true,$withObject=false) {
  512. $ret = array();
  513. if (!empty($hash)) {
  514. $querySelect = "SELECT `hash`";
  515. $queryFrom = " FROM `".DB_PREFIX."_link` AS t";
  516. $queryWhere = " WHERE ".$this->_decideLinkTypeForQuery();
  517. $queryWhere .= " AND t.hash = '".$this->DB->real_escape_string($hash)."'";
  518. $query = $this->DB->query($querySelect.$queryFrom.$queryWhere);
  519. if (!empty($query) && $query->num_rows == 1) {
  520. $linkObj = new Link($this->DB);
  521. if($fullInfo === true) {
  522. $ret = $linkObj->load($hash);
  523. }
  524. else {
  525. $ret = $linkObj->loadShortInfo($hash);
  526. }
  527. if($withObject === true) {
  528. $ret = array(
  529. 'data' => $ret,
  530. 'obj' => $linkObj
  531. );
  532. }
  533. }
  534. }
  535. return $ret;
  536. }
  537. /**
  538. * Delete link by given hash
  539. * @param $hash
  540. * @return bool
  541. */
  542. public function deleteLink($hash) {
  543. $ret = false;
  544. if (!empty($hash)) {
  545. $linkData = $this->loadLink($hash,false,true);
  546. if(!empty($linkData)) {
  547. $linkData['obj']->deleteRelations();
  548. $queryStr = "DELETE FROM `" . DB_PREFIX . "_link`
  549. WHERE `hash` = '" . $this->DB->real_escape_string($hash) . "'";
  550. $query = $this->DB->query($queryStr);
  551. if (!empty($query)) {
  552. $ret = true;
  553. }
  554. }
  555. }
  556. return $ret;
  557. }
  558. /**
  559. * Export given link for download as a xml file
  560. * @param $hash
  561. * @param bool $linkObj Use already existing link obj
  562. * @return bool
  563. */
  564. public function exportLinkData($hash,$linkObj=false) {
  565. $ret = false;
  566. if (!empty($hash)) {
  567. $linkData = $this->loadLink($hash, true, true);
  568. if (!empty($linkData)) {
  569. $data = $linkData;
  570. }
  571. }
  572. elseif(!empty($linkObj) && is_a($linkObj,'Link')) {
  573. $data = $linkObj->getData();
  574. }
  575. if(!empty($data) && isset($data['link'])) {
  576. require_once 'lib/import-export.class.php';
  577. $ImEx = new ImportExport();
  578. $ret = $ImEx->createSingleLinkExportXML($data);
  579. }
  580. return $ret;
  581. }
  582. /**
  583. * for simpler management we have the search data in a separate column
  584. * it is not fancy or even technical nice but it damn works
  585. */
  586. public function updateSearchIndex() {
  587. $ret = false;
  588. $allLinks = array();
  589. $queryStr = "SELECT hash FROM `".DB_PREFIX."_link`";
  590. $query = $this->DB->query($queryStr);
  591. if(!empty($query) && $query->num_rows > 0) {
  592. $allLinks = $query->fetch_all(MYSQLI_ASSOC);
  593. }
  594. if(!empty($allLinks)) {
  595. foreach($allLinks as $link) {
  596. $LinkObj = new Link($this->DB);
  597. $l = $LinkObj->load($link['hash']);
  598. $searchStr = $l['title'];
  599. $searchStr .= ' '.$l['description'];
  600. $searchStr .= ' '.implode(' ',$l['tags']);
  601. $searchStr .= ' '.implode(' ',$l['categories']);
  602. $searchStr = trim($searchStr);
  603. $searchStr = strtolower($searchStr);
  604. # now update the search string
  605. $queryStr = "UPDATE `".DB_PREFIX."_link`
  606. SET `search` = '".$this->DB->real_escape_string($searchStr)."'
  607. WHERE `hash` = '".$this->DB->real_escape_string($link['hash'])."'";
  608. $this->DB->query($queryStr);
  609. unset($LinkObj,$l,$searchStr,$t,$c,$queryStr);
  610. }
  611. $ret = true;
  612. }
  613. return $ret;
  614. }
  615. /**
  616. * process the given xml file. Based on the export file
  617. * options are overwrite => true|false
  618. * @param $file
  619. * @param $options
  620. * @return array
  621. */
  622. public function processImportFile($file, $options) {
  623. $ret = array(
  624. 'status' => 'error',
  625. 'message' => 'Processing error'
  626. );
  627. $links = array();
  628. require_once 'lib/import-export.class.php';
  629. $ImEx = new ImportExport();
  630. try {
  631. $ImEx->loadImportFile($file);
  632. $links = $ImEx->parseImportFile();
  633. }
  634. catch (Exception $e) {
  635. $ret['message'] = $e->getMessage();
  636. }
  637. $_existing = 0;
  638. $_new = 0;
  639. if(!empty($links)) {
  640. $_amount = count($links);
  641. foreach($links as $linkToImport) {
  642. $do = false;
  643. if($this->_linkExistsById($linkToImport['id'])) {
  644. if(isset($options['overwrite']) && $options['overwrite'] === true) {
  645. $linkObj = new Link($this->DB);
  646. $linkObj->load($linkToImport['hash']);
  647. $do = $linkObj->update($linkToImport);
  648. }
  649. $_existing++;
  650. }
  651. else {
  652. $linkObj = new Link($this->DB);
  653. $this->DB->begin_transaction(MYSQLI_TRANS_START_READ_WRITE);
  654. try{
  655. $do = $linkObj->create(array(
  656. 'hash' => $linkToImport['hash'],
  657. 'link' => $linkToImport['link'],
  658. 'status' => $linkToImport['private'],
  659. 'description' => $linkToImport['description'],
  660. 'title' => $linkToImport['title'],
  661. 'search' => '',
  662. 'image' => $linkToImport['image']
  663. ), true);
  664. } catch (Exception $e) {
  665. continue;
  666. }
  667. if(!empty($do)) {
  668. $linkToImport['catArr'] = Summoner::prepareTagOrCategoryStr($linkToImport['category']);
  669. $linkToImport['tagArr'] = Summoner::prepareTagOrCategoryStr($linkToImport['tag']);
  670. if(!empty($linkToImport['catArr'])) {
  671. foreach($linkToImport['catArr'] as $c) {
  672. $catObj = new Category($this->DB);
  673. $catObj->initbystring($c);
  674. $catObj->setRelation($do);
  675. unset($catObj);
  676. }
  677. }
  678. if(!empty($linkToImport['tagArr'])) {
  679. foreach($linkToImport['tagArr'] as $t) {
  680. $tagObj = new Tag($this->DB);
  681. $tagObj->initbystring($t);
  682. $tagObj->setRelation($do);
  683. unset($tagObj);
  684. }
  685. }
  686. $this->DB->commit();
  687. $this->updateSearchIndex();
  688. }
  689. else {
  690. $this->DB->rollback();
  691. }
  692. $_new++;
  693. }
  694. }
  695. if(isset($options['overwrite']) && $options['overwrite'] === true) {
  696. $_msg = "Found $_amount link(s) to import. Overwritten $_existing existing and imported $_new new one(s).";
  697. }
  698. else {
  699. $_msg = "Found $_amount link(s) to import. Skipped $_existing existing and imported $_new new one(s).";
  700. }
  701. $ret = array(
  702. 'status' => 'success',
  703. 'message' => $_msg
  704. );
  705. }
  706. return $ret;
  707. }
  708. /**
  709. * Return the query string for the correct status type
  710. * @return string
  711. */
  712. private function _decideLinkTypeForQuery() {
  713. switch ($this->_queryStatus) {
  714. case 1:
  715. $ret = "t.status IN (2,1)";
  716. break;
  717. case 3:
  718. $ret = "t.status = 3";
  719. break;
  720. default:
  721. $ret = "t.status = 2";
  722. }
  723. return $ret;
  724. }
  725. /**
  726. * Check if given id (not hash) exists in link database
  727. * @param $id
  728. * @return bool
  729. */
  730. private function _linkExistsById($id) {
  731. $ret = false;
  732. if(!empty($id)) {
  733. $queryStr = "SELECT `id`
  734. FROM `" . DB_PREFIX . "_link`
  735. WHERE `id` = '" . $this->DB->real_escape_string($id) . "'";
  736. $query = $this->DB->query($queryStr);
  737. if(!empty($query) && $query->num_rows > 0) {
  738. $ret = true;
  739. }
  740. }
  741. return $ret;
  742. }
  743. }