SavedSearches.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Saved searches managing
  5. *
  6. * @package PhpMyAdmin
  7. */
  8. namespace PhpMyAdmin;
  9. use PhpMyAdmin\Message;
  10. use PhpMyAdmin\Relation;
  11. use PhpMyAdmin\Response;
  12. use PhpMyAdmin\Util;
  13. /**
  14. * Saved searches managing
  15. *
  16. * @package PhpMyAdmin
  17. */
  18. class SavedSearches
  19. {
  20. /**
  21. * Global configuration
  22. * @var array
  23. */
  24. private $_config = null;
  25. /**
  26. * Id
  27. * @var int|null
  28. */
  29. private $_id = null;
  30. /**
  31. * Username
  32. * @var string
  33. */
  34. private $_username = null;
  35. /**
  36. * DB name
  37. * @var string
  38. */
  39. private $_dbname = null;
  40. /**
  41. * Saved search name
  42. * @var string
  43. */
  44. private $_searchName = null;
  45. /**
  46. * Criterias
  47. * @var array
  48. */
  49. private $_criterias = null;
  50. /**
  51. * @var Relation $relation
  52. */
  53. private $relation;
  54. /**
  55. * Public constructor
  56. *
  57. * @param array $config Global configuration
  58. */
  59. public function __construct(array $config)
  60. {
  61. $this->setConfig($config);
  62. $this->relation = new Relation();
  63. }
  64. /**
  65. * Setter of id
  66. *
  67. * @param int|null $searchId Id of search
  68. *
  69. * @return static
  70. */
  71. public function setId($searchId)
  72. {
  73. $searchId = (int)$searchId;
  74. if (empty($searchId)) {
  75. $searchId = null;
  76. }
  77. $this->_id = $searchId;
  78. return $this;
  79. }
  80. /**
  81. * Getter of id
  82. *
  83. * @return int|null
  84. */
  85. public function getId()
  86. {
  87. return $this->_id;
  88. }
  89. /**
  90. * Setter of searchName
  91. *
  92. * @param string $searchName Saved search name
  93. *
  94. * @return static
  95. */
  96. public function setSearchName($searchName)
  97. {
  98. $this->_searchName = $searchName;
  99. return $this;
  100. }
  101. /**
  102. * Getter of searchName
  103. *
  104. * @return string
  105. */
  106. public function getSearchName()
  107. {
  108. return $this->_searchName;
  109. }
  110. /**
  111. * Setter of config
  112. *
  113. * @param array $config Global configuration
  114. *
  115. * @return static
  116. */
  117. public function setConfig(array $config)
  118. {
  119. $this->_config = $config;
  120. return $this;
  121. }
  122. /**
  123. * Getter of config
  124. *
  125. * @return array
  126. */
  127. public function getConfig()
  128. {
  129. return $this->_config;
  130. }
  131. /**
  132. * Setter for criterias
  133. *
  134. * @param array|string $criterias Criterias of saved searches
  135. * @param bool $json Criterias are in JSON format
  136. *
  137. * @return static
  138. */
  139. public function setCriterias($criterias, $json = false)
  140. {
  141. if (true === $json && is_string($criterias)) {
  142. $this->_criterias = json_decode($criterias, true);
  143. return $this;
  144. }
  145. $aListFieldsToGet = array(
  146. 'criteriaColumn',
  147. 'criteriaSort',
  148. 'criteriaShow',
  149. 'criteria',
  150. 'criteriaAndOrRow',
  151. 'criteriaAndOrColumn',
  152. 'rows',
  153. 'TableList'
  154. );
  155. $data = array();
  156. $data['criteriaColumnCount'] = count($criterias['criteriaColumn']);
  157. foreach ($aListFieldsToGet as $field) {
  158. if (isset($criterias[$field])) {
  159. $data[$field] = $criterias[$field];
  160. }
  161. }
  162. /* Limit amount of rows */
  163. if (!isset($data['rows'])) {
  164. $data['rows'] = 0;
  165. } else {
  166. $data['rows'] = min(
  167. max(0, intval($data['rows'])),
  168. 100
  169. );
  170. }
  171. for ($i = 0; $i <= $data['rows']; $i++) {
  172. $data['Or' . $i] = $criterias['Or' . $i];
  173. }
  174. $this->_criterias = $data;
  175. return $this;
  176. }
  177. /**
  178. * Getter for criterias
  179. *
  180. * @return array
  181. */
  182. public function getCriterias()
  183. {
  184. return $this->_criterias;
  185. }
  186. /**
  187. * Setter for username
  188. *
  189. * @param string $username Username
  190. *
  191. * @return static
  192. */
  193. public function setUsername($username)
  194. {
  195. $this->_username = $username;
  196. return $this;
  197. }
  198. /**
  199. * Getter for username
  200. *
  201. * @return string
  202. */
  203. public function getUsername()
  204. {
  205. return $this->_username;
  206. }
  207. /**
  208. * Setter for DB name
  209. *
  210. * @param string $dbname DB name
  211. *
  212. * @return static
  213. */
  214. public function setDbname($dbname)
  215. {
  216. $this->_dbname = $dbname;
  217. return $this;
  218. }
  219. /**
  220. * Getter for DB name
  221. *
  222. * @return string
  223. */
  224. public function getDbname()
  225. {
  226. return $this->_dbname;
  227. }
  228. /**
  229. * Save the search
  230. *
  231. * @return boolean
  232. */
  233. public function save()
  234. {
  235. if (null == $this->getSearchName()) {
  236. $message = Message::error(
  237. __('Please provide a name for this bookmarked search.')
  238. );
  239. $response = Response::getInstance();
  240. $response->setRequestStatus($message->isSuccess());
  241. $response->addJSON('fieldWithError', 'searchName');
  242. $response->addJSON('message', $message);
  243. exit;
  244. }
  245. if (null == $this->getUsername()
  246. || null == $this->getDbname()
  247. || null == $this->getSearchName()
  248. || null == $this->getCriterias()
  249. ) {
  250. $message = Message::error(
  251. __('Missing information to save the bookmarked search.')
  252. );
  253. $response = Response::getInstance();
  254. $response->setRequestStatus($message->isSuccess());
  255. $response->addJSON('message', $message);
  256. exit;
  257. }
  258. $savedSearchesTbl
  259. = Util::backquote($this->_config['cfgRelation']['db']) . "."
  260. . Util::backquote($this->_config['cfgRelation']['savedsearches']);
  261. //If it's an insert.
  262. if (null === $this->getId()) {
  263. $wheres = array(
  264. "search_name = '" . $GLOBALS['dbi']->escapeString($this->getSearchName())
  265. . "'"
  266. );
  267. $existingSearches = $this->getList($wheres);
  268. if (!empty($existingSearches)) {
  269. $message = Message::error(
  270. __('An entry with this name already exists.')
  271. );
  272. $response = Response::getInstance();
  273. $response->setRequestStatus($message->isSuccess());
  274. $response->addJSON('fieldWithError', 'searchName');
  275. $response->addJSON('message', $message);
  276. exit;
  277. }
  278. $sqlQuery = "INSERT INTO " . $savedSearchesTbl
  279. . "(`username`, `db_name`, `search_name`, `search_data`)"
  280. . " VALUES ("
  281. . "'" . $GLOBALS['dbi']->escapeString($this->getUsername()) . "',"
  282. . "'" . $GLOBALS['dbi']->escapeString($this->getDbname()) . "',"
  283. . "'" . $GLOBALS['dbi']->escapeString($this->getSearchName()) . "',"
  284. . "'" . $GLOBALS['dbi']->escapeString(json_encode($this->getCriterias()))
  285. . "')";
  286. $result = (bool) $this->relation->queryAsControlUser($sqlQuery);
  287. if (!$result) {
  288. return false;
  289. }
  290. $this->setId($GLOBALS['dbi']->insertId());
  291. return true;
  292. }
  293. //Else, it's an update.
  294. $wheres = array(
  295. "id != " . $this->getId(),
  296. "search_name = '" . $GLOBALS['dbi']->escapeString($this->getSearchName()) . "'"
  297. );
  298. $existingSearches = $this->getList($wheres);
  299. if (!empty($existingSearches)) {
  300. $message = Message::error(
  301. __('An entry with this name already exists.')
  302. );
  303. $response = Response::getInstance();
  304. $response->setRequestStatus($message->isSuccess());
  305. $response->addJSON('fieldWithError', 'searchName');
  306. $response->addJSON('message', $message);
  307. exit;
  308. }
  309. $sqlQuery = "UPDATE " . $savedSearchesTbl
  310. . "SET `search_name` = '"
  311. . $GLOBALS['dbi']->escapeString($this->getSearchName()) . "', "
  312. . "`search_data` = '"
  313. . $GLOBALS['dbi']->escapeString(json_encode($this->getCriterias())) . "' "
  314. . "WHERE id = " . $this->getId();
  315. return (bool) $this->relation->queryAsControlUser($sqlQuery);
  316. }
  317. /**
  318. * Delete the search
  319. *
  320. * @return boolean
  321. */
  322. public function delete()
  323. {
  324. if (null == $this->getId()) {
  325. $message = Message::error(
  326. __('Missing information to delete the search.')
  327. );
  328. $response = Response::getInstance();
  329. $response->setRequestStatus($message->isSuccess());
  330. $response->addJSON('fieldWithError', 'searchId');
  331. $response->addJSON('message', $message);
  332. exit;
  333. }
  334. $savedSearchesTbl
  335. = Util::backquote($this->_config['cfgRelation']['db']) . "."
  336. . Util::backquote($this->_config['cfgRelation']['savedsearches']);
  337. $sqlQuery = "DELETE FROM " . $savedSearchesTbl
  338. . "WHERE id = '" . $GLOBALS['dbi']->escapeString($this->getId()) . "'";
  339. return (bool) $this->relation->queryAsControlUser($sqlQuery);
  340. }
  341. /**
  342. * Load the current search from an id.
  343. *
  344. * @return bool Success
  345. */
  346. public function load()
  347. {
  348. if (null == $this->getId()) {
  349. $message = Message::error(
  350. __('Missing information to load the search.')
  351. );
  352. $response = Response::getInstance();
  353. $response->setRequestStatus($message->isSuccess());
  354. $response->addJSON('fieldWithError', 'searchId');
  355. $response->addJSON('message', $message);
  356. exit;
  357. }
  358. $savedSearchesTbl = Util::backquote($this->_config['cfgRelation']['db'])
  359. . "."
  360. . Util::backquote($this->_config['cfgRelation']['savedsearches']);
  361. $sqlQuery = "SELECT id, search_name, search_data "
  362. . "FROM " . $savedSearchesTbl . " "
  363. . "WHERE id = '" . $GLOBALS['dbi']->escapeString($this->getId()) . "' ";
  364. $resList = $this->relation->queryAsControlUser($sqlQuery);
  365. if (false === ($oneResult = $GLOBALS['dbi']->fetchArray($resList))) {
  366. $message = Message::error(__('Error while loading the search.'));
  367. $response = Response::getInstance();
  368. $response->setRequestStatus($message->isSuccess());
  369. $response->addJSON('fieldWithError', 'searchId');
  370. $response->addJSON('message', $message);
  371. exit;
  372. }
  373. $this->setSearchName($oneResult['search_name'])
  374. ->setCriterias($oneResult['search_data'], true);
  375. return true;
  376. }
  377. /**
  378. * Get the list of saved searches of a user on a DB
  379. *
  380. * @param string[] $wheres List of filters
  381. *
  382. * @return array List of saved searches or empty array on failure
  383. */
  384. public function getList(array $wheres = array())
  385. {
  386. if (null == $this->getUsername()
  387. || null == $this->getDbname()
  388. ) {
  389. return array();
  390. }
  391. $savedSearchesTbl = Util::backquote($this->_config['cfgRelation']['db'])
  392. . "."
  393. . Util::backquote($this->_config['cfgRelation']['savedsearches']);
  394. $sqlQuery = "SELECT id, search_name "
  395. . "FROM " . $savedSearchesTbl . " "
  396. . "WHERE "
  397. . "username = '" . $GLOBALS['dbi']->escapeString($this->getUsername()) . "' "
  398. . "AND db_name = '" . $GLOBALS['dbi']->escapeString($this->getDbname()) . "' ";
  399. foreach ($wheres as $where) {
  400. $sqlQuery .= "AND " . $where . " ";
  401. }
  402. $sqlQuery .= "order by search_name ASC ";
  403. $resList = $this->relation->queryAsControlUser($sqlQuery);
  404. $list = array();
  405. while ($oneResult = $GLOBALS['dbi']->fetchArray($resList)) {
  406. $list[$oneResult['id']] = $oneResult['search_name'];
  407. }
  408. return $list;
  409. }
  410. }