PageRenderTime 27ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/libraries/HTTP_Session/Session/Container/MDB2.php

https://bitbucket.org/thomashii/vtigercrm-6-for-postgresql
PHP | 364 lines | 185 code | 26 blank | 153 comment | 33 complexity | 19206fc71d812e89eb44137391de61d8 MD5 | raw file
Possible License(s): Apache-2.0, LGPL-3.0, LGPL-2.1, GPL-2.0, GPL-3.0
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. /**
  4. * Database container for session data
  5. *
  6. * PEAR::MDB2 database container
  7. *
  8. * PHP version 4
  9. *
  10. * LICENSE: This source file is subject to version 3.0 of the PHP license
  11. * that is available through the world-wide-web at the following URI:
  12. * http://www.php.net/license/3_0.txt. If you did not receive a copy of
  13. * the PHP License and are unable to obtain it through the web, please
  14. * send a note to license@php.net so we can mail you a copy immediately.
  15. *
  16. * @category HTTP
  17. * @package HTTP_Session
  18. * @author Alexander Radivanovich <info@wwwlab.net>
  19. * @author David Costa <gurugeek@php.net>
  20. * @author Michael Metz <pear.metz@speedpartner.de>
  21. * @author Stefan Neufeind <pear.neufeind@speedpartner.de>
  22. * @author Torsten Roehr <torsten.roehr@gmx.de>
  23. * @copyright 1997-2005 The PHP Group
  24. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  25. * @version CVS: $Id: MDB2.php,v 1.5 2007/07/14 12:11:55 troehr Exp $
  26. * @link http://pear.php.net/package/HTTP_Session
  27. * @since File available since Release 0.5.0
  28. */
  29. require_once 'HTTP/Session/Container.php';
  30. require_once 'MDB2.php';
  31. /**
  32. * Database container for session data
  33. *
  34. * Create the following table to store session data
  35. * <code>
  36. * CREATE TABLE `sessiondata` (
  37. * `id` CHAR(32) NOT NULL,
  38. * `expiry` INT UNSIGNED NOT NULL DEFAULT 0,
  39. * `data` TEXT NOT NULL,
  40. * PRIMARY KEY (`id`)
  41. * );
  42. * </code>
  43. *
  44. * @category HTTP
  45. * @package HTTP_Session
  46. * @author David Costa <gurugeek@php.net>
  47. * @author Michael Metz <pear.metz@speedpartner.de>
  48. * @author Stefan Neufeind <pear.neufeind@speedpartner.de>
  49. * @author Torsten Roehr <torsten.roehr@gmx.de>
  50. * @copyright 1997-2005 The PHP Group
  51. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  52. * @version Release: @package_version@
  53. * @link http://pear.php.net/package/HTTP_Session
  54. * @since Class available since Release 0.5.0
  55. */
  56. class HTTP_Session_Container_MDB2 extends HTTP_Session_Container
  57. {
  58. /**
  59. * MDB2 connection object
  60. *
  61. * @var object MDB2
  62. * @access private
  63. */
  64. var $db = null;
  65. /**
  66. * Session data cache id
  67. *
  68. * @var mixed
  69. * @access private
  70. */
  71. var $crc = false;
  72. /**
  73. * Constructor method
  74. *
  75. * $options is an array with the options.<br>
  76. * The options are:
  77. * <ul>
  78. * <li>'dsn' - The DSN string</li>
  79. * <li>'table' - Table with session data, default is 'sessiondata'</li>
  80. * <li>'autooptimize' - Boolean, 'true' to optimize
  81. * the table on garbage collection, default is 'false'.</li>
  82. * </ul>
  83. *
  84. * @param array $options Options
  85. *
  86. * @access public
  87. * @return void
  88. */
  89. function HTTP_Session_Container_MDB2($options)
  90. {
  91. $this->_setDefaults();
  92. if (is_array($options)) {
  93. $this->_parseOptions($options);
  94. } else {
  95. $this->options['dsn'] = $options;
  96. }
  97. }
  98. /**
  99. * Connect to database by using the given DSN string
  100. *
  101. * @param string $dsn DSN string
  102. *
  103. * @access private
  104. * @return mixed Object on error, otherwise bool
  105. */
  106. function _connect($dsn)
  107. {
  108. if (is_string($dsn) || is_array($dsn)) {
  109. $this->db = MDB2::connect($dsn);
  110. } else if (is_object($dsn) && is_a($dsn, 'MDB2_Driver_Common')) {
  111. $this->db = $dsn;
  112. } else if (is_object($dsn) && MDB2::isError($dsn)) {
  113. return $dsn;
  114. } else {
  115. return new PEAR_Error("The given dsn was not valid in file " . __FILE__
  116. . " at line " . __LINE__,
  117. 41,
  118. PEAR_ERROR_RETURN,
  119. null,
  120. null
  121. );
  122. }
  123. if (MDB2::isError($this->db)) {
  124. return new MDB2_Error($this->db->code, PEAR_ERROR_DIE);
  125. }
  126. return true;
  127. }
  128. /**
  129. * Set some default options
  130. *
  131. * @access private
  132. * @return void
  133. */
  134. function _setDefaults()
  135. {
  136. $this->options['dsn'] = null;
  137. $this->options['table'] = 'sessiondata';
  138. $this->options['autooptimize'] = false;
  139. }
  140. /**
  141. * Establish connection to a database
  142. *
  143. * @param string $save_path Save path
  144. * @param string $session_name Session name
  145. *
  146. * @return bool
  147. */
  148. function open($save_path, $session_name)
  149. {
  150. if (MDB2::isError($this->_connect($this->options['dsn']))) {
  151. return false;
  152. } else {
  153. return true;
  154. }
  155. }
  156. /**
  157. * Free resources
  158. *
  159. * @return bool
  160. */
  161. function close()
  162. {
  163. return true;
  164. }
  165. /**
  166. * Read session data
  167. *
  168. * @param string $id Session id
  169. *
  170. * @return mixed
  171. */
  172. function read($id)
  173. {
  174. $query = sprintf("SELECT data FROM %s WHERE id = %s AND expiry >= %d",
  175. $this->options['table'],
  176. $this->db->quote(md5($id), 'text'),
  177. time());
  178. $result = $this->db->queryOne($query);
  179. if (MDB2::isError($result)) {
  180. $this->db->raiseError($result->code, PEAR_ERROR_DIE);
  181. return false;
  182. }
  183. $this->crc = strlen($result) . crc32($result);
  184. return $result;
  185. }
  186. /**
  187. * Write session data
  188. *
  189. * @param string $id Session id
  190. * @param mixed $data Data
  191. *
  192. * @return bool
  193. */
  194. function write($id, $data)
  195. {
  196. if ((false !== $this->crc) &&
  197. ($this->crc === strlen($data) . crc32($data))) {
  198. // $_SESSION hasn't been touched, no need to update the blob column
  199. $query = sprintf("UPDATE %s SET expiry = %d WHERE id = %s",
  200. $this->options['table'],
  201. time() + ini_get('session.gc_maxlifetime'),
  202. $this->db->quote(md5($id), 'text'));
  203. } else {
  204. // Check if table row already exists
  205. $query = sprintf("SELECT COUNT(id) FROM %s WHERE id = %s",
  206. $this->options['table'],
  207. $this->db->quote(md5($id), 'text'));
  208. $result = $this->db->queryOne($query);
  209. if (MDB2::isError($result)) {
  210. $this->db->raiseError($result->code, PEAR_ERROR_DIE);
  211. return false;
  212. }
  213. if (0 == intval($result)) {
  214. // Insert new row into table
  215. $query = sprintf("INSERT INTO %s (id, expiry, data) VALUES (%s, %d, %s)",
  216. $this->options['table'],
  217. $this->db->quote(md5($id), 'text'),
  218. time() + ini_get('session.gc_maxlifetime'),
  219. $this->db->quote($data, 'text'));
  220. } else {
  221. // Update existing row
  222. $query = sprintf("UPDATE %s SET expiry = %d, data = %s WHERE id = %s",
  223. $this->options['table'],
  224. time() + ini_get('session.gc_maxlifetime'),
  225. $this->db->quote($data, 'text'),
  226. $this->db->quote(md5($id), 'text'));
  227. }
  228. }
  229. $result = $this->db->query($query);
  230. if (MDB2::isError($result)) {
  231. $this->db->raiseError($result->code, PEAR_ERROR_DIE);
  232. return false;
  233. }
  234. return true;
  235. }
  236. /**
  237. * Destroy session data
  238. *
  239. * @param string $id Session id
  240. *
  241. * @return bool
  242. */
  243. function destroy($id)
  244. {
  245. $query = sprintf("DELETE FROM %s WHERE id = %s",
  246. $this->options['table'],
  247. $this->db->quote(md5($id), 'text'));
  248. $result = $this->db->query($query);
  249. if (MDB2::isError($result)) {
  250. $this->db->raiseError($result->code, PEAR_ERROR_DIE);
  251. return false;
  252. }
  253. return true;
  254. }
  255. /**
  256. * Replicate session data to table specified in option 'replicateBeforeDestroy'
  257. *
  258. * @param string $targetTable Table to replicate to
  259. * @param string $id Id of record to replicate
  260. *
  261. * @access private
  262. * @return bool
  263. */
  264. function replicate($targetTable, $id = null)
  265. {
  266. if (is_null($id)) {
  267. $id = HTTP_Session::id();
  268. }
  269. // Check if table row already exists
  270. $query = sprintf("SELECT COUNT(id) FROM %s WHERE id = %s",
  271. $targetTable,
  272. $this->db->quote(md5($id), 'text'));
  273. $result = $this->db->queryOne($query);
  274. if (MDB2::isError($result)) {
  275. $this->db->raiseError($result->code, PEAR_ERROR_DIE);
  276. return false;
  277. }
  278. // Insert new row into dest table
  279. if (0 == intval($result)) {
  280. $query = sprintf("INSERT INTO %s SELECT * FROM %s WHERE id = %s",
  281. $targetTable,
  282. $this->options['table'],
  283. $this->db->quote(md5($id), 'text'));
  284. } else {
  285. // Update existing row
  286. $query = sprintf("UPDATE %s dst, %s src SET dst.expiry = src.expiry, dst.data = src.data WHERE dst.id = src.id AND src.id = %s",
  287. $targetTable,
  288. $this->options['table'],
  289. $this->db->quote(md5($id), 'text'));
  290. }
  291. $result = $this->db->query($query);
  292. if (MDB2::isError($result)) {
  293. $this->db->raiseError($result->code, PEAR_ERROR_DIE);
  294. return false;
  295. }
  296. return true;
  297. }
  298. /**
  299. * Garbage collection
  300. *
  301. * @param int $maxlifetime Maximum lifetime
  302. *
  303. * @return bool
  304. */
  305. function gc($maxlifetime)
  306. {
  307. $query = sprintf("DELETE FROM %s WHERE expiry < %d",
  308. $this->options['table'],
  309. time());
  310. $result = $this->db->query($query);
  311. if (MDB2::isError($result)) {
  312. $this->db->raiseError($result->code, PEAR_ERROR_DIE);
  313. return false;
  314. }
  315. if ($this->options['autooptimize']) {
  316. switch($this->db->phptype) {
  317. case 'mysql':
  318. $query = sprintf("OPTIMIZE TABLE %s", $this->options['table']);
  319. break;
  320. case 'pgsql':
  321. $query = sprintf("VACUUM %s", $this->options['table']);
  322. break;
  323. default:
  324. $query = null;
  325. break;
  326. }
  327. if (isset($query)) {
  328. $result = $this->db->query($query);
  329. if (MDB2::isError($result)) {
  330. $this->db->raiseError($result->code, PEAR_ERROR_DIE);
  331. return false;
  332. }
  333. }
  334. }
  335. return true;
  336. }
  337. }
  338. ?>