SQLite3.php 10 KB

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