PageRenderTime 27ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/vb/db/query.php

https://gitlab.com/elasa/vb-elasa.ir
PHP | 622 lines | 402 code | 64 blank | 156 comment | 43 complexity | ad147452876fbada2c958edc7fbe6511 MD5 | raw file
  1. <?php if (!defined('VB_ENTRY')) die('Access denied.');
  2. /*======================================================================*\
  3. || #################################################################### ||
  4. || # vBulletin 4.2.2
  5. || # ---------------------------------------------------------------- # ||
  6. || # Copyright 2000-2013 vBulletin Solutions Inc. All Rights Reserved. ||
  7. || # This file may not be redistributed in whole or significant part. # ||
  8. || # ---------------- VBULLETIN IS NOT FREE SOFTWARE ---------------- # ||
  9. || # http://www.vbulletin.com | http://www.vbulletin.com/license.html # ||
  10. || #################################################################### ||
  11. \*======================================================================*/
  12. /**
  13. * The vB core class.
  14. * The vB core class.
  15. * Everything required at the core level should be accessible through this.
  16. *
  17. * The core class performs initialisation for error handling, exception handling,
  18. * application instatiation and optionally debug handling.
  19. *
  20. * @TODO: Much of what goes on in global.php and init.php will be handled, or at
  21. * least called here during the initialisation process. This will be moved over as
  22. * global.php is refactored.
  23. *
  24. * @package vBulletin
  25. * @version $Revision: 28823 $
  26. * @since $Date: 2008-12-16 17:43:04 +0000 (Tue, 16 Dec 2008) $
  27. * @copyright vBulletin Solutions Inc.
  28. */
  29. class vB_dB_Query
  30. {
  31. /** This class is called by the new vB_dB_Assertor database class
  32. * It does the actual execution. See the vB_dB_Assertor class for more information
  33. * $queryid can be either the id of a query from the dbqueries table, or the
  34. * name of a table.
  35. *
  36. * if it is the name of a table , $params MUST include 'type' of either update, insert, select, or delete.
  37. *
  38. * $params includes a list of parameters. Here's how it gets interpreted.
  39. *
  40. * If the queryid was the name of a table and type was "update", one of the params
  41. * must be the primary key of the table. All the other parameters will be matched against
  42. * the table field names, and appropriate fields will be updated. The return value will
  43. * be false if an error is generated and true otherwise
  44. *
  45. * If the queryid was the name of a table and type was "delete", one of the params
  46. * must be the primary key of the table. All the other parameters will be ignored
  47. * The return value will be false if an error is generated and true otherwise
  48. *
  49. * If the queryid was the name of a table and type was "insert", all the parameters will be
  50. * matched against the table field names, and appropriate fields will be set in the insert.
  51. * The return value is the primary key of the inserted record.
  52. *
  53. * If the queryid was the name of a table and type was "select", all the parameters will be
  54. * matched against the table field names, and appropriate fields will be part of the
  55. * "where" clause of the select. The return value will be a vB_dB_Result object
  56. * The return value is the primary key of the inserted record.
  57. *
  58. * If the queryid is the key of a record in the dbqueries table then each params
  59. * value will be matched to the query. If there are missing parameters we will return false.
  60. * If the query generates an error we return false, and otherwise we return either true,
  61. * or an inserted id, or a recordset.
  62. *
  63. **/
  64. /*Properties====================================================================*/
  65. /** The database connection **/
  66. protected $db = false;
  67. /** The user info ***/
  68. protected $userinfo = false;
  69. /** query_type - s (select), u (update), i (insert), d (delete), and t (table... we don't know yet
  70. **/
  71. protected $query_type = false;
  72. /** are we ready to execute? **/
  73. protected $data_loaded = false;
  74. /** are we ready to execute? **/
  75. protected $datafields = false;
  76. /** What is the primary key of the table, if applicable? */
  77. protected $primarykey = false;
  78. /** What is the text of the stored query from the dictionary, if applicable? */
  79. protected $query_string = false;
  80. /** The parameters are are going to use to populate the query data */
  81. protected $params = false;
  82. /** The array from a describe statement for database structure, if applicable? */
  83. protected $structure = false;
  84. /** The replacement variables from a stored query**/
  85. protected $replacements = false;
  86. /** The original query id **/
  87. protected $queryid = false;
  88. /** The most recent error **/
  89. protected $error = false;
  90. /** All errors for this query **/
  91. protected $errors = array();
  92. /** sortorder, for select queries only (obviously) **/
  93. protected $sortorder = false;
  94. /** This is the definition for tables we will process through. It saves a
  95. * database query to put them here.
  96. * **/
  97. protected $table_data = array();
  98. protected $query_data = array();
  99. /*Initialisation================================================================*/
  100. /** validates that we know what to do with this queryid
  101. *
  102. * @param string id of the query
  103. * @param mixed the shared db object
  104. * @param array the user information
  105. *
  106. ***/
  107. public function __construct($queryid, &$db, $userinfo)
  108. {
  109. $this->db = $db;
  110. $this->userinfo = $userinfo;
  111. $this->queryid = $queryid;
  112. $class = 'vB_Db_' . $this->db_type . '_QueryDefs';
  113. $query_defs = new $class();
  114. $this->query_data = $query_defs->getQueryData();
  115. $this->table_data = $query_defs->getTableData();
  116. if ($this->query_data[$queryid])
  117. {
  118. $this->query_type = $this->query_data[$queryid]['querytype'];
  119. $this->query_string = $this->query_data[$queryid]['query_string'];
  120. $matches = false;
  121. preg_match_all('#\{.+?\}#', $this->query_data[$queryid]['query_string'], $matches);
  122. $this->replacements = $matches;
  123. return;
  124. }
  125. if ($this->table_data[$queryid])
  126. {
  127. $this->query_type = 't';
  128. $this->structure = $this->table_data[$queryid]['structure'];
  129. $this->primarykey = $this->table_data[$queryid]['key'];
  130. return;
  131. }
  132. //Now let's see if this is a stored query.
  133. $this_query = $this->db->query_first("SELECT * from " . TABLE_PREFIX . "dbquery
  134. WHERE dbqueryid = '" . $this->db->escape_string($queryid) . "'");
  135. $this->queryid = $queryid;
  136. if ($this_query)
  137. {
  138. $this->query_type = $this_query['querytype'];
  139. $this->query_string = $this_query['query_string'];
  140. $matches = false;
  141. preg_match_all('#\{.+?\}#', $this_query['query_string'], $matches);
  142. $this->replacements = $matches;
  143. return;
  144. }
  145. //We need to see if this is a table, and if so get the structure
  146. //If this isn't a table name we'll generate an error.
  147. $reporterror = $db->reporterror;
  148. $db->hide_errors();
  149. $structure = $this->db->query_read("describe " . TABLE_PREFIX . "$queryid;");
  150. if ($reporterror)
  151. {
  152. $db->show_errors();
  153. }
  154. if (!$structure)
  155. {
  156. return false;
  157. }
  158. $this->query_type = 't';
  159. $this->structure = array();
  160. while($record = $this->db->fetch_array($structure))
  161. {
  162. $this->structure[] = $record['Field'];
  163. if ($record['key'] == 'PRI')
  164. {
  165. $this->primarykey = $record['field'];
  166. }
  167. }
  168. }
  169. /** This loads and validates the data- ensures we have all we need
  170. *
  171. * @param array the data for the query
  172. ***/
  173. public function setQuery($params, $sortorder)
  174. {
  175. //Let's first check that we have a valid type, and if necessary we
  176. // have a valid key.
  177. if (!$this->query_type OR (!$this->query_string AND !$this->structure))
  178. {
  179. return false;
  180. }
  181. reset($params);
  182. if (is_array(current($params)))
  183. {
  184. $checkvals = current($params);
  185. }
  186. else
  187. {
  188. $checkvals = $params;
  189. }
  190. //We're not going to do the detailed match. At this step we should
  191. //only do the obvious. So if we are a stored query and either params or the
  192. //replacements are empty but not the other, then we can't execute.
  193. switch($this->query_type)
  194. {
  195. case 'i': //We are a stored query insert.
  196. case 'u': //We are a stored query update.
  197. case 's': //We are a stored query select.
  198. case 'd': //We are a stored query delete.
  199. if (count($checkvals) AND ($this->query_string) AND !count($this->replacements))
  200. {
  201. return false;
  202. }
  203. if (count($this->replacements) AND ($this->query_string) AND !count($checkvals))
  204. {
  205. return false;
  206. }
  207. //We at least are potentially good.
  208. break;
  209. case 't': //We are a table. We don't know yet what we are executing
  210. if (!$checkvals['type'])
  211. {
  212. return false;
  213. }
  214. switch($checkvals['type'])
  215. {
  216. case 'i': //We are a table insert.
  217. case 'u': //We are a table update.
  218. case 'd': //We are a table delete.
  219. if (count($checkvals) < 2)
  220. {
  221. return false;
  222. }
  223. $this->query_type = $checkvals['type'];
  224. break;
  225. case 's': //We are a table select. We don't need anything
  226. $this->query_type = 's';
  227. break;
  228. default:
  229. return false;
  230. } // switch
  231. break;
  232. default:
  233. return false;
  234. ;
  235. } // switch
  236. if (is_array(current($params)) OR ($this->query_type == 's'))
  237. {
  238. $this->params = $params;
  239. }
  240. else
  241. {
  242. $this->params = array($params);
  243. }
  244. if ($sortorder)
  245. {
  246. $this->sortorder = $sortorder;
  247. }
  248. $this->data_loaded = true;
  249. return true;
  250. }
  251. /** This function is the public interface to actually execute the SQL.
  252. *
  253. * @return mixed
  254. **/
  255. public function execSQL()
  256. {
  257. $result_type = 'vB_dB_' . $this->db_type . '_result';
  258. //If we don't have the data loaded, we can't execute.
  259. if (!$this->query_type OR !$this->data_loaded)
  260. {
  261. return false;
  262. }
  263. switch($this->query_type)
  264. {
  265. case 'u': //We are a stored query update.
  266. $result = $this->doUpdates($result_type);
  267. break;
  268. case 'i': //We are a stored query insert.
  269. $result = $this->doInserts($result_type);
  270. break;
  271. case 's': //We are a stored query select.
  272. return $this->doSelect($result_type);
  273. break;
  274. case 'd': //We are a stored query delete.
  275. $result = $this->doDeletes($result_type);
  276. ;
  277. break;
  278. case 't': //We are a table. We should never have gotten here.
  279. default:
  280. return false;
  281. ;
  282. } // switch
  283. return $result;
  284. }
  285. /** This matches a series of values against a query string
  286. *
  287. * @param string The query string we want to populate
  288. * @param mixed The array of values
  289. *
  290. * It returns either a string with all the values inserted ready to execute,
  291. * or false;
  292. */
  293. private function matchValues($querystring, $values)
  294. {
  295. //The replacements are like {1}
  296. foreach ($values as $key => $value)
  297. {
  298. //See if we skip escaping this value
  299. if (array_key_exists('quotes_ok', $this->query_data[$this->queryid]) AND
  300. in_array($key, $this->query_data[$this->queryid]['quotes_ok']))
  301. {
  302. $querystring = str_replace('{'. $key . '}', $value, $querystring);
  303. }
  304. else
  305. {
  306. $querystring = str_replace('{'. $key . '}', $this->db->escape_string($value), $querystring);
  307. }
  308. }
  309. $querystring = str_replace('{TABLE_PREFIX}', TABLE_PREFIX, $querystring);
  310. //See if there are variables we didn't replace.
  311. $matches = false;
  312. if (preg_match_all('#\{.{1,32}?\}#', $querystring, $matches) > 0)
  313. {
  314. return false;
  315. }
  316. else
  317. {
  318. $querystring .= "\n/**" . $this->queryid . (defined('THIS_SCRIPT') ? '- ' . THIS_SCRIPT : '') . "**/";
  319. return $querystring;
  320. }
  321. }
  322. /** This function generates the query text against a table.
  323. *
  324. * @param char
  325. * @param array
  326. *
  327. * @return mixed
  328. **/
  329. private function buildQuery($type, $values)
  330. {
  331. $new_values = array();
  332. //first it will be useful to have an array of matches.
  333. foreach ($this->structure as $field )
  334. {
  335. if (isset($values[$field]))
  336. {
  337. if (array_key_exists('quotes_ok', $this->table_data[$this->queryid]) AND
  338. in_array($field, $this->table_data[$this->queryid]['quotes_ok']))
  339. {
  340. $new_values[$field] = "'" . $values[$field] . "'";
  341. }
  342. else
  343. {
  344. $new_values[$field] = "'" . $this->db->escape_string($values[$field]) . "'";
  345. }
  346. }
  347. }
  348. switch($this->query_type){
  349. case 'u':
  350. //we need a primary key value
  351. if (!$values[$this->primarykey])
  352. {
  353. return false;
  354. }
  355. unset($new_values[$this->primarykey]);
  356. foreach ($new_values as $key => $value)
  357. {
  358. $new_values[$key] = $key . "=" . $value;
  359. }
  360. return "UPDATE " . TABLE_PREFIX . $this->queryid . " SET " . implode($new_values, ',') . " WHERE " .
  361. $this->primarykey . "='" . $this->db->escape_string($values[$this->primarykey]) . "' " .
  362. "\n/**" . $this->queryid . (defined('THIS_SCRIPT') ? '- ' . THIS_SCRIPT : '') . "**/";
  363. break;
  364. case 'i':
  365. return "INSERT INTO " . TABLE_PREFIX . $this->queryid . " (" . implode(array_keys($new_values), ',') . ")
  366. VALUES(" . implode($new_values, ',') . ")" .
  367. "\n/**" . $this->queryid . (defined('THIS_SCRIPT') ? '- ' . THIS_SCRIPT : '') . "**/";
  368. break;
  369. case 'd':
  370. //we need a primary key value
  371. if ($values[$this->primarykey] AND !empty($values[$this->primarykey]))
  372. {
  373. return "DELETE FROM " . TABLE_PREFIX . $this->queryid . " WHERE " .
  374. $this->primarykey . "='" . $this->db->escape_string($values[$this->primarykey]) . "' " .
  375. "\n/**" . $this->queryid . (defined('THIS_SCRIPT') ? '- ' . THIS_SCRIPT : '') . "**/";
  376. }
  377. foreach ($new_values as $key => $value)
  378. {
  379. $new_values[$key] = $key . "=" . $value;
  380. }
  381. return "DELETE FROM " . TABLE_PREFIX . $this->queryid . " WHERE " . implode($new_values, ' AND ') .
  382. "\n/**" . $this->queryid . (defined('THIS_SCRIPT') ? '- ' . THIS_SCRIPT : '') . "**/";
  383. break;
  384. case 's':
  385. foreach ($new_values as $key => $value)
  386. {
  387. $new_values[$key] = $key . "=" . $value;
  388. }
  389. return "SELECT * FROM " . TABLE_PREFIX . $this->queryid . " WHERE " . implode($new_values, ' AND ')
  390. . ($this->sortorder ? " ORDER BY " . $this->sortorder : '') .
  391. "\n/**" . $this->queryid . (defined('THIS_SCRIPT') ? '- ' . THIS_SCRIPT : '') . "**/" ;
  392. break;
  393. default:
  394. return false;
  395. ;
  396. } // switch
  397. }
  398. /** This function does the updates and returns array of the number of updates
  399. *
  400. * @param char
  401. *
  402. * @return mixed
  403. **/
  404. protected function doUpdates($result_type)
  405. {
  406. $results = array();
  407. if ($this->query_string)
  408. {
  409. foreach ($this->params as $params)
  410. {
  411. if ($querystring = $this->matchValues($this->query_string, $params))
  412. {
  413. $this->db->query_write($querystring);
  414. $this->error = $this->db->error();
  415. $results[] = $this->db->affected_rows();
  416. }
  417. else
  418. {
  419. $results[] = false;
  420. }
  421. }
  422. }
  423. else if ($this->structure)
  424. {
  425. foreach ($this->params as $params)
  426. {
  427. if ($querystring = $this->buildQuery($this->type, $params))
  428. {
  429. $this->db->query_write($querystring);
  430. $this->error = $this->db->error();
  431. $results[] = $this->db->affected_rows();
  432. }
  433. else
  434. {
  435. $results[] = false;
  436. }
  437. }
  438. }
  439. return $results;
  440. }
  441. /** This function does the inserts and returns (if applicable) the new keys
  442. *
  443. * @param char
  444. *
  445. * @return mixed
  446. **/
  447. protected function doInserts($result_type)
  448. {
  449. $results = array();
  450. if ($this->query_string)
  451. {
  452. foreach ($this->params as $params)
  453. {
  454. if ($querystring = $this->matchValues($this->query_string, $params))
  455. {
  456. $this->db->query_write($querystring);
  457. $this->error = $this->db->error();
  458. $results[] = $this->db->insert_id();
  459. }
  460. else
  461. {
  462. $results[] = false;
  463. }
  464. }
  465. }
  466. else if ($this->structure)
  467. {
  468. foreach ($this->params as $params)
  469. {
  470. if ($querystring = $this->buildQuery($this->type, $params))
  471. {
  472. $this->db->query_write($querystring);
  473. $this->error = $this->db->error();
  474. $results[] = $this->db->insert_id();
  475. }
  476. else
  477. {
  478. $results[] = false;
  479. }
  480. }
  481. }
  482. return $results;
  483. }
  484. /** This function does the selects and returns a result object
  485. *
  486. * @param char
  487. *
  488. * @return object
  489. **/
  490. protected function doSelect($result_type)
  491. {
  492. $results = array();
  493. if ($this->query_string)
  494. {
  495. $querystring = $this->matchValues($this->query_string, $this->params);
  496. }
  497. else if ($this->structure)
  498. {
  499. $querystring = $this->buildQuery($this->type, $this->params);
  500. }
  501. if (!$querystring)
  502. {
  503. return false;
  504. }
  505. $resultclass = 'vB_dB_' . $this->db_type . '_result';
  506. $result = new $resultclass($this->db, $querystring);
  507. return $result;
  508. }
  509. /** This function does the deletes and returns a flag to indicate whether the delete worked
  510. *
  511. * @param char
  512. *
  513. * @return boolean
  514. **/
  515. protected function doDeletes($result_type)
  516. {
  517. $results = array();
  518. if ($this->query_string)
  519. {
  520. foreach ($this->params as $params)
  521. {
  522. if ($querystring = $this->matchValues($this->query_string, $params))
  523. {
  524. $this->db->query_write($querystring);
  525. $this->error = $this->db->error();
  526. $results[] = empty($this->error);
  527. }
  528. else
  529. {
  530. $results[] = false;
  531. }
  532. }
  533. }
  534. else if ($this->structure)
  535. {
  536. foreach ($this->params as $params)
  537. {
  538. if ($querystring = $this->buildQuery($this->type, $params))
  539. {
  540. $this->db->query_write($querystring);
  541. $this->error = $this->db->error();
  542. $results[] = empty($this->error);
  543. }
  544. else
  545. {
  546. $results[] = false;
  547. }
  548. }
  549. }
  550. return $results;
  551. }
  552. }
  553. /*======================================================================*\
  554. || ####################################################################
  555. || # SVN=> $Revision=> 28823 $
  556. || ####################################################################
  557. \*======================================================================*/