SQLite3.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. <?php
  2. /**
  3. * PHPExcel_CachedObjectStorage_SQLite3
  4. *
  5. * Copyright (c) 2006 - 2015 PHPExcel
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. *
  21. * @category PHPExcel
  22. * @package PHPExcel_CachedObjectStorage
  23. * @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
  24. * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
  25. * @version ##VERSION##, ##DATE##
  26. */
  27. class PHPExcel_CachedObjectStorage_SQLite3 extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache
  28. {
  29. /**
  30. * Database table name
  31. *
  32. * @var string
  33. */
  34. private $TableName = null;
  35. /**
  36. * Database handle
  37. *
  38. * @var resource
  39. */
  40. private $DBHandle = null;
  41. /**
  42. * Prepared statement for a SQLite3 select query
  43. *
  44. * @var SQLite3Stmt
  45. */
  46. private $selectQuery;
  47. /**
  48. * Prepared statement for a SQLite3 insert query
  49. *
  50. * @var SQLite3Stmt
  51. */
  52. private $insertQuery;
  53. /**
  54. * Prepared statement for a SQLite3 update query
  55. *
  56. * @var SQLite3Stmt
  57. */
  58. private $updateQuery;
  59. /**
  60. * Prepared statement for a SQLite3 delete query
  61. *
  62. * @var SQLite3Stmt
  63. */
  64. private $deleteQuery;
  65. /**
  66. * Store cell data in cache for the current cell object if it's "dirty",
  67. * and the 'nullify' the current cell object
  68. *
  69. * @return void
  70. * @throws PHPExcel_Exception
  71. */
  72. protected function storeData()
  73. {
  74. if ($this->currentCellIsDirty && !empty($this->currentObjectID)) {
  75. $this->currentObject->detach();
  76. $this->insertQuery->bindValue('id', $this->currentObjectID, SQLITE3_TEXT);
  77. $this->insertQuery->bindValue('data', serialize($this->currentObject), SQLITE3_BLOB);
  78. $result = $this->insertQuery->execute();
  79. if ($result === false) {
  80. throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
  81. }
  82. $this->currentCellIsDirty = false;
  83. }
  84. $this->currentObjectID = $this->currentObject = null;
  85. }
  86. /**
  87. * Add or Update a cell in cache identified by coordinate address
  88. *
  89. * @param string $pCoord Coordinate address of the cell to update
  90. * @param PHPExcel_Cell $cell Cell to update
  91. * @return PHPExcel_Cell
  92. * @throws PHPExcel_Exception
  93. */
  94. public function addCacheData($pCoord, PHPExcel_Cell $cell)
  95. {
  96. if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) {
  97. $this->storeData();
  98. }
  99. $this->currentObjectID = $pCoord;
  100. $this->currentObject = $cell;
  101. $this->currentCellIsDirty = true;
  102. return $cell;
  103. }
  104. /**
  105. * Get cell at a specific coordinate
  106. *
  107. * @param string $pCoord Coordinate of the cell
  108. * @throws PHPExcel_Exception
  109. * @return PHPExcel_Cell Cell that was found, or null if not found
  110. */
  111. public function getCacheData($pCoord)
  112. {
  113. if ($pCoord === $this->currentObjectID) {
  114. return $this->currentObject;
  115. }
  116. $this->storeData();
  117. $this->selectQuery->bindValue('id', $pCoord, SQLITE3_TEXT);
  118. $cellResult = $this->selectQuery->execute();
  119. if ($cellResult === false) {
  120. throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
  121. }
  122. $cellData = $cellResult->fetchArray(SQLITE3_ASSOC);
  123. if ($cellData === false) {
  124. // Return null if requested entry doesn't exist in cache
  125. return null;
  126. }
  127. // Set current entry to the requested entry
  128. $this->currentObjectID = $pCoord;
  129. $this->currentObject = unserialize($cellData['value']);
  130. // Re-attach this as the cell's parent
  131. $this->currentObject->attach($this);
  132. // Return requested entry
  133. return $this->currentObject;
  134. }
  135. /**
  136. * Is a value set for an indexed cell?
  137. *
  138. * @param string $pCoord Coordinate address of the cell to check
  139. * @return boolean
  140. */
  141. public function isDataSet($pCoord)
  142. {
  143. if ($pCoord === $this->currentObjectID) {
  144. return true;
  145. }
  146. // Check if the requested entry exists in the cache
  147. $this->selectQuery->bindValue('id', $pCoord, SQLITE3_TEXT);
  148. $cellResult = $this->selectQuery->execute();
  149. if ($cellResult === false) {
  150. throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
  151. }
  152. $cellData = $cellResult->fetchArray(SQLITE3_ASSOC);
  153. return ($cellData === false) ? false : true;
  154. }
  155. /**
  156. * Delete a cell in cache identified by coordinate address
  157. *
  158. * @param string $pCoord Coordinate address of the cell to delete
  159. * @throws PHPExcel_Exception
  160. */
  161. public function deleteCacheData($pCoord)
  162. {
  163. if ($pCoord === $this->currentObjectID) {
  164. $this->currentObject->detach();
  165. $this->currentObjectID = $this->currentObject = null;
  166. }
  167. // Check if the requested entry exists in the cache
  168. $this->deleteQuery->bindValue('id', $pCoord, SQLITE3_TEXT);
  169. $result = $this->deleteQuery->execute();
  170. if ($result === false) {
  171. throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
  172. }
  173. $this->currentCellIsDirty = false;
  174. }
  175. /**
  176. * Move a cell object from one address to another
  177. *
  178. * @param string $fromAddress Current address of the cell to move
  179. * @param string $toAddress Destination address of the cell to move
  180. * @return boolean
  181. */
  182. public function moveCell($fromAddress, $toAddress)
  183. {
  184. if ($fromAddress === $this->currentObjectID) {
  185. $this->currentObjectID = $toAddress;
  186. }
  187. $this->deleteQuery->bindValue('id', $toAddress, SQLITE3_TEXT);
  188. $result = $this->deleteQuery->execute();
  189. if ($result === false) {
  190. throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
  191. }
  192. $this->updateQuery->bindValue('toid', $toAddress, SQLITE3_TEXT);
  193. $this->updateQuery->bindValue('fromid', $fromAddress, SQLITE3_TEXT);
  194. $result = $this->updateQuery->execute();
  195. if ($result === false) {
  196. throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
  197. }
  198. return true;
  199. }
  200. /**
  201. * Get a list of all cell addresses currently held in cache
  202. *
  203. * @return string[]
  204. */
  205. public function getCellList()
  206. {
  207. if ($this->currentObjectID !== null) {
  208. $this->storeData();
  209. }
  210. $query = "SELECT id FROM kvp_".$this->TableName;
  211. $cellIdsResult = $this->DBHandle->query($query);
  212. if ($cellIdsResult === false) {
  213. throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
  214. }
  215. $cellKeys = array();
  216. while ($row = $cellIdsResult->fetchArray(SQLITE3_ASSOC)) {
  217. $cellKeys[] = $row['id'];
  218. }
  219. return $cellKeys;
  220. }
  221. /**
  222. * Clone the cell collection
  223. *
  224. * @param PHPExcel_Worksheet $parent The new worksheet
  225. * @return void
  226. */
  227. public function copyCellCollection(PHPExcel_Worksheet $parent)
  228. {
  229. $this->currentCellIsDirty;
  230. $this->storeData();
  231. // Get a new id for the new table name
  232. $tableName = str_replace('.', '_', $this->getUniqueID());
  233. if (!$this->DBHandle->exec('CREATE TABLE kvp_'.$tableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)
  234. AS SELECT * FROM kvp_'.$this->TableName)
  235. ) {
  236. throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
  237. }
  238. // Copy the existing cell cache file
  239. $this->TableName = $tableName;
  240. }
  241. /**
  242. * Clear the cell collection and disconnect from our parent
  243. *
  244. * @return void
  245. */
  246. public function unsetWorksheetCells()
  247. {
  248. if (!is_null($this->currentObject)) {
  249. $this->currentObject->detach();
  250. $this->currentObject = $this->currentObjectID = null;
  251. }
  252. // detach ourself from the worksheet, so that it can then delete this object successfully
  253. $this->parent = null;
  254. // Close down the temporary cache file
  255. $this->__destruct();
  256. }
  257. /**
  258. * Initialise this new cell collection
  259. *
  260. * @param PHPExcel_Worksheet $parent The worksheet for this cell collection
  261. */
  262. public function __construct(PHPExcel_Worksheet $parent)
  263. {
  264. parent::__construct($parent);
  265. if (is_null($this->DBHandle)) {
  266. $this->TableName = str_replace('.', '_', $this->getUniqueID());
  267. $_DBName = ':memory:';
  268. $this->DBHandle = new SQLite3($_DBName);
  269. if ($this->DBHandle === false) {
  270. throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
  271. }
  272. if (!$this->DBHandle->exec('CREATE TABLE kvp_'.$this->TableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)')) {
  273. throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
  274. }
  275. }
  276. $this->selectQuery = $this->DBHandle->prepare("SELECT value FROM kvp_".$this->TableName." WHERE id = :id");
  277. $this->insertQuery = $this->DBHandle->prepare("INSERT OR REPLACE INTO kvp_".$this->TableName." VALUES(:id,:data)");
  278. $this->updateQuery = $this->DBHandle->prepare("UPDATE kvp_".$this->TableName." SET id=:toId WHERE id=:fromId");
  279. $this->deleteQuery = $this->DBHandle->prepare("DELETE FROM kvp_".$this->TableName." WHERE id = :id");
  280. }
  281. /**
  282. * Destroy this cell collection
  283. */
  284. public function __destruct()
  285. {
  286. if (!is_null($this->DBHandle)) {
  287. $this->DBHandle->exec('DROP TABLE kvp_'.$this->TableName);
  288. $this->DBHandle->close();
  289. }
  290. $this->DBHandle = null;
  291. }
  292. /**
  293. * Identify whether the caching method is currently available
  294. * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
  295. *
  296. * @return boolean
  297. */
  298. public static function cacheMethodIsAvailable()
  299. {
  300. if (!class_exists('SQLite3', false)) {
  301. return false;
  302. }
  303. return true;
  304. }
  305. }