Automatically exported from code.google.com/p/planningalerts
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

359 lines
11 KiB

  1. <?php
  2. /**
  3. * $Header: /home/ppcvs/paypal_php_sdk/Log/mdb2.php,v 1.1 2006/02/19 08:22:29 dennis Exp $
  4. *
  5. * @version $Revision: 1.1 $
  6. * @package Log
  7. */
  8. /** PEAR's MDB2 package */
  9. require_once 'MDB2.php';
  10. MDB2::loadFile('Date');
  11. /**
  12. * The Log_mdb2 class is a concrete implementation of the Log:: abstract class
  13. * which sends messages to an SQL server. Each entry occupies a separate row
  14. * in the database.
  15. *
  16. * This implementation uses PEAR's MDB2 database abstraction layer.
  17. *
  18. * CREATE TABLE log_table (
  19. * id INT NOT NULL,
  20. * logtime TIMESTAMP NOT NULL,
  21. * ident CHAR(16) NOT NULL,
  22. * priority INT NOT NULL,
  23. * message VARCHAR(200),
  24. * PRIMARY KEY (id)
  25. * );
  26. *
  27. * @author Lukas Smith <smith@backendmedia.com>
  28. * @author Jon Parise <jon@php.net>
  29. * @since Log 1.9.0
  30. * @package Log
  31. */
  32. class Log_mdb2 extends Log
  33. {
  34. /**
  35. * Variable containing the DSN information.
  36. * @var mixed
  37. * @access private
  38. */
  39. var $_dsn = '';
  40. /**
  41. * Array containing our set of DB configuration options.
  42. * @var array
  43. * @access private
  44. */
  45. var $_options = array('persistent' => true);
  46. /**
  47. * Object holding the database handle.
  48. * @var object
  49. * @access private
  50. */
  51. var $_db = null;
  52. /**
  53. * Resource holding the prepared statement handle.
  54. * @var resource
  55. * @access private
  56. */
  57. var $_statement = null;
  58. /**
  59. * Flag indicating that we're using an existing database connection.
  60. * @var boolean
  61. * @access private
  62. */
  63. var $_existingConnection = false;
  64. /**
  65. * String holding the database table to use.
  66. * @var string
  67. * @access private
  68. */
  69. var $_table = 'log_table';
  70. /**
  71. * String holding the name of the ID sequence.
  72. * @var string
  73. * @access private
  74. */
  75. var $_sequence = 'log_id';
  76. /**
  77. * Maximum length of the $ident string. This corresponds to the size of
  78. * the 'ident' column in the SQL table.
  79. * @var integer
  80. * @access private
  81. */
  82. var $_identLimit = 16;
  83. /**
  84. * Set of field types used in the database table.
  85. * @var array
  86. * @access private
  87. */
  88. var $_types = array(
  89. 'id' => 'integer',
  90. 'logtime' => 'timestamp',
  91. 'ident' => 'text',
  92. 'priority' => 'text',
  93. 'message' => 'clob'
  94. );
  95. /**
  96. * Constructs a new sql logging object.
  97. *
  98. * @param string $name The target SQL table.
  99. * @param string $ident The identification field.
  100. * @param array $conf The connection configuration array.
  101. * @param int $level Log messages up to and including this level.
  102. * @access public
  103. */
  104. function Log_mdb2($name, $ident = '', $conf = array(),
  105. $level = PEAR_LOG_DEBUG)
  106. {
  107. $this->_id = md5(microtime());
  108. $this->_table = $name;
  109. $this->_mask = Log::UPTO($level);
  110. /* If an options array was provided, use it. */
  111. if (isset($conf['options']) && is_array($conf['options'])) {
  112. $this->_options = $conf['options'];
  113. }
  114. /* If a specific sequence name was provided, use it. */
  115. if (!empty($conf['sequence'])) {
  116. $this->_sequence = $conf['sequence'];
  117. }
  118. /* If a specific sequence name was provided, use it. */
  119. if (isset($conf['identLimit'])) {
  120. $this->_identLimit = $conf['identLimit'];
  121. }
  122. /* Now that the ident limit is confirmed, set the ident string. */
  123. $this->setIdent($ident);
  124. /* If an existing database connection was provided, use it. */
  125. if (isset($conf['db'])) {
  126. $this->_db = &$conf['db'];
  127. $this->_existingConnection = true;
  128. $this->_opened = true;
  129. } elseif (isset($conf['singleton'])) {
  130. $this->_db = &MDB2::singleton($conf['singleton'], $this->_options);
  131. $this->_existingConnection = true;
  132. $this->_opened = true;
  133. } else {
  134. $this->_dsn = $conf['dsn'];
  135. }
  136. }
  137. /**
  138. * Opens a connection to the database, if it has not already
  139. * been opened. This is implicitly called by log(), if necessary.
  140. *
  141. * @return boolean True on success, false on failure.
  142. * @access public
  143. */
  144. function open()
  145. {
  146. if (!$this->_opened) {
  147. /* Use the DSN and options to create a database connection. */
  148. $this->_db = &MDB2::connect($this->_dsn, $this->_options);
  149. if (PEAR::isError($this->_db)) {
  150. return false;
  151. }
  152. /* Create a prepared statement for repeated use in log(). */
  153. if (!$this->_prepareStatement()) {
  154. return false;
  155. }
  156. /* We now consider out connection open. */
  157. $this->_opened = true;
  158. }
  159. return $this->_opened;
  160. }
  161. /**
  162. * Closes the connection to the database if it is still open and we were
  163. * the ones that opened it. It is the caller's responsible to close an
  164. * existing connection that was passed to us via $conf['db'].
  165. *
  166. * @return boolean True on success, false on failure.
  167. * @access public
  168. */
  169. function close()
  170. {
  171. /* If we have a statement object, free it. */
  172. if (is_object($this->_statement)) {
  173. $this->_statement->free();
  174. $this->_statement = null;
  175. }
  176. /* If we opened the database connection, disconnect it. */
  177. if ($this->_opened && !$this->_existingConnection) {
  178. $this->_opened = false;
  179. return $this->_db->disconnect();
  180. }
  181. return ($this->_opened === false);
  182. }
  183. /**
  184. * Sets this Log instance's identification string. Note that this
  185. * SQL-specific implementation will limit the length of the $ident string
  186. * to sixteen (16) characters.
  187. *
  188. * @param string $ident The new identification string.
  189. *
  190. * @access public
  191. * @since Log 1.8.5
  192. */
  193. function setIdent($ident)
  194. {
  195. $this->_ident = substr($ident, 0, $this->_identLimit);
  196. }
  197. /**
  198. * Inserts $message to the currently open database. Calls open(),
  199. * if necessary. Also passes the message along to any Log_observer
  200. * instances that are observing this Log.
  201. *
  202. * @param mixed $message String or object containing the message to log.
  203. * @param string $priority The priority of the message. Valid
  204. * values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
  205. * PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
  206. * PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
  207. * @return boolean True on success or false on failure.
  208. * @access public
  209. */
  210. function log($message, $priority = null)
  211. {
  212. /* If a priority hasn't been specified, use the default value. */
  213. if ($priority === null) {
  214. $priority = $this->_priority;
  215. }
  216. /* Abort early if the priority is above the maximum logging level. */
  217. if (!$this->_isMasked($priority)) {
  218. return false;
  219. }
  220. /* If the connection isn't open and can't be opened, return failure. */
  221. if (!$this->_opened && !$this->open()) {
  222. return false;
  223. }
  224. /* If we don't already have a statement object, create one. */
  225. if (!is_object($this->_statement) && !$this->_prepareStatement()) {
  226. return false;
  227. }
  228. /* Extract the string representation of the message. */
  229. $message = $this->_extractMessage($message);
  230. /* Build our set of values for this log entry. */
  231. $values = array(
  232. 'id' => $this->_db->nextId($this->_sequence),
  233. 'logtime' => MDB2_Date::mdbNow(),
  234. 'ident' => $this->_ident,
  235. 'priority' => $priority,
  236. 'message' => $message
  237. );
  238. /* Execute the SQL query for this log entry insertion. */
  239. $this->_db->expectError(MDB2_ERROR_NOSUCHTABLE);
  240. $result = &$this->_statement->execute($values);
  241. $this->_db->popExpect();
  242. /* Attempt to handle any errors. */
  243. if (PEAR::isError($result)) {
  244. /* We can only handle MDB2_ERROR_NOSUCHTABLE errors. */
  245. if ($result->getCode() != MDB2_ERROR_NOSUCHTABLE) {
  246. return false;
  247. }
  248. /* Attempt to create the target table. */
  249. if (!$this->_createTable()) {
  250. return false;
  251. }
  252. /* Recreate our prepared statement resource. */
  253. $this->_statement->free();
  254. if (!$this->_prepareStatement()) {
  255. return false;
  256. }
  257. /* Attempt to re-execute the insertion query. */
  258. $result = $this->_statement->execute($values);
  259. if (PEAR::isError($result)) {
  260. return false;
  261. }
  262. }
  263. $this->_announce(array('priority' => $priority, 'message' => $message));
  264. return true;
  265. }
  266. /**
  267. * Create the log table in the database.
  268. *
  269. * @return boolean True on success or false on failure.
  270. * @access private
  271. */
  272. function _createTable()
  273. {
  274. $this->_db->loadModule('Manager');
  275. $result = $this->_db->manager->createTable(
  276. $this->_table,
  277. array(
  278. 'id' => array('type' => $this->_types['id']),
  279. 'logtime' => array('type' => $this->_types['logtime']),
  280. 'ident' => array('type' => $this->_types['ident']),
  281. 'priority' => array('type' => $this->_types['priority']),
  282. 'message' => array('type' => $this->_types['message'])
  283. )
  284. );
  285. if (PEAR::isError($result)) {
  286. return false;
  287. }
  288. $result = $this->_db->manager->createIndex(
  289. $this->_table,
  290. 'unique_id',
  291. array('fields' => array('id' => true), 'unique' => true)
  292. );
  293. if (PEAR::isError($result)) {
  294. return false;
  295. }
  296. return true;
  297. }
  298. /**
  299. * Prepare the SQL insertion statement.
  300. *
  301. * @return boolean True if the statement was successfully created.
  302. *
  303. * @access private
  304. * @since Log 1.9.0
  305. */
  306. function _prepareStatement()
  307. {
  308. $this->_statement = &$this->_db->prepare(
  309. 'INSERT INTO ' . $this->_table .
  310. ' (id, logtime, ident, priority, message)' .
  311. ' VALUES(:id, :logtime, :ident, :priority, :message)',
  312. $this->_types);
  313. /* Return success if we didn't generate an error. */
  314. return (PEAR::isError($this->_statement) === false);
  315. }
  316. }