Guest User

Untitled

a guest
Nov 8th, 2017
166
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.21 KB | None | 0 0
  1. <?php
  2. /**
  3. * @package mysql-database
  4. */
  5.  
  6. /**
  7. * MySQL Database
  8. *
  9. * A singleton object which provides convenience methods for interfacing with
  10. * a MySQL database in PHP 5. You can get the object's instance using the
  11. * static {@link getInstance()} method. Being a singleton object, this class
  12. * only supports one open database connection at a time and idealy suited to
  13. * single-threaded applications. You can read
  14. * about {@link http://php.net/manual/en/language.oop5.patterns.php the singleton
  15. * pattern in the PHP manual}.
  16. *
  17. * <b>Getting Started</b>
  18. * <code>
  19. * $db = MySqlDatabase::getInstance();
  20. *
  21. * try {
  22. * $db->connect('localhost', 'user', 'password', 'database_name');
  23. * }
  24. * catch (Exception $e) {
  25. * die($e->getMessage());
  26. * }
  27. * </code>
  28. *
  29. * @package mysql-database
  30. * @author Micah Carrick
  31. * @copyright (c) 2010 - Micah Carrick
  32. * @version 2.0
  33. * @license BSD
  34. */
  35. class MySqlDatabase
  36. {
  37. /**
  38. * The MySQL link identifier created by {@link connect()}
  39. *
  40. * @var resource
  41. */
  42. public $link;
  43.  
  44. /**
  45. * @var string
  46. */
  47. private $conn_str;
  48.  
  49. /**
  50. * @var MySqlDatabase
  51. */
  52. private static $instance;
  53.  
  54. const MYSQL_DATE_FORMAT = 'Y-m-d';
  55. const MYSQL_TIME_FORMAT = 'H:i:s';
  56. const MYSQL_DATETIME_FORMAT = 'Y-m-d H:i:s';
  57.  
  58. const INSERT_GET_AUTO_INCREMENT_ID = 1;
  59. const INSERT_GET_AFFECTED_ROWS = 2;
  60.  
  61. /**
  62. * Constructor
  63. *
  64. * Private constructor as part of the singleton pattern implementation.
  65. */
  66. private function __construct() {}
  67.  
  68. /**
  69. * Connect
  70. *
  71. * Establish a connection to a MySQL database. Returns the MySQL link
  72. * link identifier or throws an exception if there is an error.
  73. *
  74. * <code>
  75. * // get an instance of the Database singleton
  76. * $db = MySqlDatabase::getInstance();
  77. *
  78. * // connect to a MySQL database (use your own login information)
  79. * try {
  80. * $db->connect('localhost', 'user', 'password', 'database_name');
  81. * }
  82. * catch (Exception $e) {
  83. * die($e->getMessage());
  84. * }
  85. * </code>
  86. *
  87. * @param string
  88. * @param string
  89. * @param string
  90. * @param string
  91. * @param boolean
  92. * @return resource
  93. */
  94. public function connect($host = "localhost:3306", $user = "*****_***", $password = "********", $database = "*******", $persistant=false)
  95. {
  96. if ($persistant) {
  97. $this->link = @mysql_pconnect($host, $user, $password);
  98. } else {
  99. $this->link = @mysqli_connect($host, $user, $password);
  100. }
  101.  
  102. if (!$this->link)
  103. {
  104. throw new Exception('Unable to establish database connection: '
  105. .mysqli_error());
  106. }
  107.  
  108. mysqli_query("SET CHARACTER SET 'utf8'");
  109.  
  110. if ($database) $this->useDatabase($database);
  111.  
  112. $version = mysqli_get_server_info();
  113. $this->conn_str = "'$database' on '$user@$host' (MySQL $version)";
  114.  
  115. return $this->link;
  116. }
  117.  
  118. /**
  119. * Delete
  120. *
  121. * Executes the DELETE statement specified in the query and returns the
  122. * value from either the PHP {@link mysql_affected_rows()} function. Throws
  123. * and exception if there is a MySQL error in the query.
  124. *
  125. * Note: With MySQL versions prior to 4.1.2, the affected rows on DELETE
  126. * statements with no WHERE clause is 0. See {@link mysql_affected_rows()}
  127. * for more information.
  128. *
  129. * @param string
  130. * @return integer
  131. */
  132. public function delete($query)
  133. {
  134. return $this->updateOrDelete($query);
  135. }
  136.  
  137. /**
  138. * Get Connection String
  139. *
  140. * Gets a string representing the connection.
  141. *
  142. * <code>
  143. * echo $db->getConnectionString();
  144. * // example output: 'test_database' on 'web_user@localhost' (MySQL 5.1.47)
  145. * </code>
  146. *
  147. * @return string
  148. */
  149. public function getConnectionString()
  150. {
  151. return $this->conn_str;
  152. }
  153.  
  154. /**
  155. * Get Instance
  156. *
  157. * Gets the singleton instance for this object. This method should be called
  158. * statically in order to use the Database object:
  159. *
  160. * <code>
  161. * $db = MySqlDatabase::getInstance();
  162. * </code>
  163. *
  164. * @return MySqlDatabase
  165. */
  166. public static function getInstance()
  167. {
  168. if (!isset(self::$instance))
  169. {
  170. self::$instance = new MySqlDatabase();
  171. }
  172.  
  173. return self::$instance;
  174. }
  175.  
  176. /**
  177. * Fetch One From Each Row
  178. *
  179. * Convenience method to get a single value from every row in a given
  180. * query. This is usefull in situations where you know that the result will
  181. * only have only one column of data and you need that all in a simple
  182. * array.
  183. *
  184. * <code>
  185. *
  186. * $query = "SELECT name FROM users";
  187. * $names = $db->fetchOneFromEachRow($query);
  188. * echo 'Users: ' . implode(', ', $names);
  189. * </code>
  190. *
  191. * @param string
  192. * @return array
  193. */
  194. public function fetchOneFromEachRow($query)
  195. {
  196. $rval = array();
  197.  
  198. foreach ($this->iterate($query, MySqlResultSet::DATA_NUMERIC_ARRAY) as $row) {
  199. $rval[] = $row[0];
  200. }
  201.  
  202. return $rval;
  203. }
  204.  
  205. /**
  206. * Fetch One Row
  207. *
  208. * Convenience method to get a single row from a given query. This is
  209. * usefull in situations where you know that the result will only contain
  210. * one record and therefore do not need to iterate over it.
  211. *
  212. * You can
  213. * optionally specify the type of data to be returned (object or array)
  214. * using one of the MySqlResultSet Data Constants. The default is
  215. * {@link MySqlResultSet::DATA_OBJECT}.
  216. *
  217. * <code>
  218. * // get one row of data
  219. * $query = "SELECT first, last FROM users WHERE user_id = 24 LIMIT 1";
  220. * $row = $db->fetchOneRow($query);
  221. * echo $row->foo;
  222. * echo $row->bar;
  223. * </code>
  224. *
  225. * @param string
  226. * @param integer
  227. * @return mixed
  228. */
  229. public function fetchOneRow($query, $data_type=MySqlResultSet::DATA_OBJECT)
  230. {
  231. $result = new MySqlResultSet($query, $data_type, $this->link);
  232. $result->rewind();
  233. $row = $result->current();
  234.  
  235. return $row;
  236. }
  237.  
  238. /**
  239. * Fetch One
  240. *
  241. * Convenience method to get a single value from a single row. Returns the
  242. * value if the query returned a record, false if there were no results, or
  243. * throws an exception if there was an error with the query.
  244. *
  245. * <code>
  246. * // get the number of records in the 'users' table
  247. * $count = $db->fetchOne("SELECT COUNT(*) FROM users");
  248. * </code>
  249. *
  250. * @param string
  251. * @return mixed
  252. */
  253. public function fetchOne($query)
  254. {
  255. $result = new MySqlResultSet($query, MySqlResultSet::DATA_NUMERIC_ARRAY,
  256. $this->link);
  257. $result->rewind();
  258. $row = $result->current();
  259.  
  260. if (!$row) return false;
  261. else return $row[0];
  262. }
  263.  
  264. /**
  265. * Import SQL File
  266. *
  267. * Runs the queries defined in an SQL script file. The double-hyphen style
  268. * comments must have a single space after the hyphens. Hash style comments
  269. * and C-style comments are also supported.
  270. *
  271. * An optional user callback function can be specified to get information
  272. * about each MySQL statement. The user callback function takes 3
  273. * parameters: the line number as an integer, the query as a string, and the
  274. * result of the query as a boolean.
  275. *
  276. * <code>
  277. * function import_sql_callback($line_number, $sql_query, $result)
  278. * {
  279. * echo "Line $line_number: $sql_query ";
  280. * if ($result) echo "(OK)<br/>";
  281. * else echo "(FAIL)<br/>";
  282. * }
  283. * </code>
  284. *
  285. * You can optionally specify whether or not to abort importing statements
  286. * when an SQL error occurs (defaults to 'true') in which case an exception
  287. * will be thrown for any MySQL error.
  288. *
  289. * Returns the number of queries executed from the script or throws an
  290. * exception if there is an error.
  291. *
  292. * <code>
  293. * // no callback, throw exception on MySQL errors
  294. * $number = $db->importSqlFile('queries.sql');
  295. *
  296. * // callback for each query, skip queries with MySQL errors
  297. * $number = $db->importSqlFile('queries.sql', 'import_sql_callback', false);
  298. * </code>
  299. *
  300. * TODO: Ensure this works with huge files. Might need to use fopen()
  301. *
  302. * @param string
  303. * @param string
  304. * @param boolean
  305. * @return integer
  306. */
  307. public function importSqlFile($filename, $callback=false, $abort_on_error=true)
  308. {
  309. if ($callback && !is_callable($callback)) {
  310. throw new Exception("Invalid callback function.");
  311. }
  312.  
  313. $lines = $this->loadFile($filename);
  314.  
  315. $num_queries = 0;
  316. $sql_line = 0;
  317. $sql = '';
  318. $in_comment = false;
  319.  
  320. foreach ($lines as $num => $line) {
  321.  
  322. $line = trim($line);
  323. $num++;
  324. if (empty($sql)) $sql_line = $num;
  325.  
  326. // ignore comments
  327.  
  328. if ($in_comment) {
  329. $comment = strpos($line, '*/');
  330.  
  331. if ($comment !== false) {
  332. $in_comment = false;
  333. $line = substr($line, $comment+2);
  334. } else {
  335. continue;
  336. }
  337.  
  338. } else {
  339.  
  340. $comment = strpos($line, '/*');
  341.  
  342. if ($comment !== false) {
  343.  
  344. if (strpos($line, '*/') === false) {
  345. $in_comment = true;
  346. }
  347.  
  348. $line = substr($line, 0, $comment);
  349.  
  350. } else {
  351.  
  352. // single line comments
  353.  
  354. foreach (array('-- ', '#') as $chars) {
  355. $comment = strpos($line, $chars);
  356.  
  357. if ($comment !== false) {
  358. $line = substr($line, 0, $comment);
  359. }
  360. }
  361. }
  362. }
  363.  
  364. // check if the statement is ready to be queried
  365.  
  366. $end = strpos($line, ';');
  367.  
  368. if ($end === false) {
  369. $sql .= $line;
  370. } else {
  371. $sql .= substr($line, 0, $end);
  372. $result = $this->quickQuery($sql);
  373. $num_queries++;
  374.  
  375. if (!$result && $abort_on_error) {
  376. $file = basename($filename);
  377. $error = mysqli_error($this->link);
  378. throw new Exception("Error in $file on line $sql_line: $error");
  379. }
  380.  
  381. if ($callback) {
  382. call_user_func($callback, $sql_line, $sql, $result);
  383. }
  384.  
  385. $sql = ''; // clear for next statement
  386.  
  387. }
  388. }
  389.  
  390. return $num_queries;
  391. }
  392.  
  393. /**
  394. * Is Connected
  395. *
  396. * Determines if there is a connection open to the database.
  397. *
  398. * @return boolean
  399. */
  400. public function isConnected()
  401. {
  402. if (!empty($this->link)) {
  403. return @mysqli_ping($this->link);
  404. } else {
  405. return false;
  406. }
  407. }
  408.  
  409. // insertPhpArray
  410. // insertSqlArray
  411. // sqlval()
  412.  
  413. /**
  414. * Insert
  415. *
  416. * Executes the INSERT statement specified in the query and returns the
  417. * value from either the PHP {@link mysql_insert_id()} function or the
  418. * php {@link mysql_affected_rows()} function depending on the value of the
  419. * $return_type parameter.
  420. *
  421. * <code>
  422. * $db = MySqlDatabase::getInstance();
  423. * $query = "INSERT INTO foobar (col1, col2) VALUES (1, 2), (2, 3)";
  424. * $rows = $db->insert($query, MySqlDatabase::INSERT_GET_AFFECTED_ROWS);
  425. * echo $rows; // output: 2
  426. * </code>
  427. *
  428. *
  429. * @param string
  430. * @param integer
  431. * @return integer
  432. */
  433. public function insert($query, $r_type=MySqlDatabase::INSERT_GET_AUTO_INCREMENT_ID)
  434. {
  435. $r = $this->query($query);
  436.  
  437. if ($r_type == MySqlDatabase::INSERT_GET_AFFECTED_ROWS) {
  438. return @mysqli_affected_rows($this->link);
  439. } else {
  440. return @mysqli_insert_id($this->link);
  441. }
  442. }
  443.  
  444. /**
  445. * DO NOT USE
  446. *
  447. * This was never finished... I don't think. The goal was to take a table
  448. * name, an array of column names, and an array of values and generate a
  449. * multiple record insert. You should not use this, but, you could help
  450. * out and finish or rewrite this method.
  451. *
  452. *
  453. * @param deprecated
  454. */
  455. public function smartInsert($table, $columns, $values)
  456. {
  457. if (empty($table) || !is_string($table)) {
  458. throw new Exception('The $table parameter must be specified as a string.');
  459. }
  460.  
  461. $table_sql = '`' . @mysqli_real_escape_string($table) . '`';
  462. $query = "INSERT INTO $table_sql ";
  463.  
  464. // columns
  465. if (is_string($columns)) {
  466. $columns = explode(',', $columns);
  467. }
  468.  
  469. if (is_array($columns)) {
  470. foreach ($columns as &$col) {
  471. if (!is_string($col)) {
  472. throw new Exception('The $columns parameter must be a string or an array of strings');
  473. }
  474. $col = @mysql_real_escape_string($col);
  475. }
  476. $column_sql = implode(',', $columns);
  477. $column_count = count($columns);
  478. } else {
  479. throw new Exception('The $columns parameter must be a string or an array of strings.');
  480. }
  481.  
  482. try {
  483. $column_info = array();
  484.  
  485. foreach ($this->iterate("SHOW COLUMNS FROM $table_sql") as $row) {
  486. $column_info[] = $row;
  487. }
  488. }
  489. catch (Exception $e) {
  490. throw new Exception("Could not get column information for table $table_sql.");
  491. }
  492.  
  493. $query .= "($column_sql) ";
  494.  
  495. // values
  496.  
  497. if (is_array($values)) {
  498. for ($i=0; $i < count($values); $i++) {
  499. $info = $column_info[$i];
  500. $value = $values[i];
  501.  
  502. // Where the heck did I leave off?
  503. }
  504. } else {
  505. // TODO: if only 1 column, then this will work
  506.  
  507. throw new Exception('The $values parameter must be a string or an array.');
  508. }
  509.  
  510. if (isset($column_count) && $column_count <> $value_count) {
  511. throw new Exception("Column count ($column_count) does not match values count ($value_count).");
  512. }
  513.  
  514. $query .= "VALUES ($value_sql) ";
  515.  
  516. echo $query;
  517.  
  518. }
  519.  
  520. /**
  521. * Iterate Result Set
  522. *
  523. * Returns a {@link MySQL_ResultSet} iteratable object for a query. The $type
  524. * parameter indicates the data being iterated should be an object,
  525. * a numerically indexed array, an associative array, or an array with
  526. * both numeric and associative indexes. Defaults to objects.
  527. *
  528. * <code>
  529. * $sql_query = "SELECT col1, col2 FROM table";
  530. *
  531. * // iterate as objects
  532. * foreach ($db->iterate("SELECT col1, col2 FROM table") as $row) {
  533. * echo $row->col1 . '<br/>';
  534. * echo $row->col2 . '<br/>';
  535. * }
  536. *
  537. * // iterate as both associative and numerically indexed array
  538. * foreach ($db->iterate($sql_query, MySQL_Db::DATA_ARRAY) as $row) {
  539. * echo $row[0] . '<br/>';
  540. * echo $row['col1'] . '<br/>';
  541. * }
  542. * </code>
  543. *
  544. * @param string
  545. * @param integer
  546. * @return boolean
  547. */
  548. public function iterate($sql, $data_type=MySqlResultSet::DATA_OBJECT)
  549. {
  550. return new MySqlResultSet($sql, $data_type, $this->link);
  551. }
  552.  
  553. /**
  554. * Load File
  555. *
  556. * Loads the specified filename into an array of lines. Throws an exception
  557. * if there is an error.
  558. *
  559. * @param string
  560. * @return boolean
  561. */
  562. private function loadFile($filename)
  563. {
  564. if (!file_exists($filename)) {
  565. throw new Exception("File does not exist: $filename");
  566. }
  567.  
  568. $file = @file($filename, FILE_IGNORE_NEW_LINES);
  569.  
  570. if (!$file) {
  571. throw new Exception("Could not open $filename");
  572. }
  573.  
  574. return $file;
  575. }
  576.  
  577. public function query($query)
  578. {
  579. $r = @mysqli_query($query, $this->link);
  580.  
  581. if (!$r) {
  582. throw new Exception("Query Error: " . mysqli_error());
  583. }
  584.  
  585. return $r;
  586. }
  587.  
  588. /**
  589. * Quick Query
  590. *
  591. * Executes a MySQL query and returns a boolean value indicating success
  592. * or failure. This method will close any resources opened from
  593. * SELECT, SHOW, DESCRIBE, or EXPLAIN statements and would not be very
  594. * usefull for those types of queries. This method is used internally for
  595. * importing SQL scripts.
  596. *
  597. * @param string
  598. * @return boolean
  599. */
  600. public function quickQuery($query)
  601. {
  602. $r = @mysqli_query($query, $this->link);
  603.  
  604. if (!$r) return false;
  605. if (is_resource($r)) mysqli_free_result($r);
  606.  
  607. return true;
  608. }
  609.  
  610. /**
  611. * Update
  612. *
  613. * Executes the UPDATE statement specified in the query and returns the
  614. * value from either the PHP {@link mysql_affected_rows()} function. Throws
  615. * and exception if there is a MySQL error in the query.
  616. *
  617. * Note: The number of rows affected include only those in which the new
  618. * value was not the same as the old value. See {@link mysql_affected_rows()}
  619. * for more information.
  620. *
  621. * @param string
  622. * @return integer
  623. */
  624. public function update($query)
  625. {
  626. return $this->updateOrDelete($query);
  627. }
  628.  
  629. private function updateOrDelete($query)
  630. {
  631. $r = $this->query($query);
  632. return @mysqli_affected_rows($this->link);
  633. }
  634.  
  635. /**
  636. * Use Database
  637. *
  638. * Selects the database to use. Throws an exception if there is an error
  639. * using the specified database.
  640. *
  641. * @param string
  642. * @return integer
  643. */
  644. public function useDatabase($database)
  645. {
  646. if (!@mysqli_select_db($database, $this->link))
  647. {
  648. throw new Exception('Unable to select database: ' . mysqli_error($this->link));
  649. }
  650. }
  651. }
  652.  
  653.  
  654.  
  655. ?>
Add Comment
Please, Sign In to add comment