PageRenderTime 60ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/core/inc/class/class.sqlite3db.php

https://bitbucket.org/greenbox/microframework
PHP | 299 lines | 245 code | 8 blank | 46 comment | 9 complexity | 8c4e6ff09996db19f68a1258a7fdf8c6 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-3.0
  1. <?php
  2. /**
  3. * @author Jonathan Gotti <jgotti at jgotti dot org>
  4. * @copyleft (l) 2008 Jonathan Gotti
  5. * @package class-db
  6. * @file
  7. * @since 2008-04
  8. * @license http://opensource.org/licenses/lgpl-license.php GNU Lesser General Public License
  9. * @svnInfos:
  10. * - $LastChangedDate: 2009-04-30 01:00:12 +0200 (jeu. 30 avril 2009) $
  11. * - $LastChangedRevision: 127 $
  12. * - $LastChangedBy: malko $
  13. * - $HeadURL: http://trac.jgotti.net/svn/class-db/trunk/adapters/class-sqlite3db.php $
  14. * @changelog
  15. * - 2008-07-29 - suppress a bug to avoid some error while trying to destroy twice the same last_qres.
  16. * @todo add transactions support
  17. */
  18. /**
  19. * exented db class to use with sqlite3 databases.
  20. * require php sqlite3 extension to work
  21. * @class sqlite3db
  22. */
  23. class sqlite3db extends db{
  24. public $autocreate= TRUE;
  25. public $db_file = '';
  26. public $_protect_fldname = "'";
  27. /**
  28. * create a sqlitedb object for managing locale data
  29. * if DATA_PATH is define will force access in this directory
  30. * @param string $Db_file
  31. * @return sqlitedb object
  32. */
  33. function __construct($db_file){
  34. $this->host = 'localhost';
  35. $this->db_file = $db_file;
  36. $this->conn = &$this->db; # only for better compatibility with other db implementation
  37. if(db::$autoconnect)
  38. $this->open();
  39. }
  40. ###*** REQUIRED METHODS FOR EXTENDED CLASS ***###
  41. /** open connection to database */
  42. function open(){
  43. //prevent multiple db open
  44. if($this->db)
  45. return $this->db;
  46. if(! $this->db_file )
  47. return FALSE;
  48. if(! (is_file($this->db_file) || $this->autocreate) )
  49. return FALSE;
  50. if( $this->db = sqlite3_open($this->db_file)){
  51. return $this->db;
  52. }else{
  53. $this->set_error(__FUNCTION__);
  54. return FALSE;
  55. }
  56. }
  57. /** close connection to previously opened database */
  58. function close(){
  59. if( !is_null($this->db) ){
  60. if($this->last_qres){
  61. sqlite3_query_close($this->last_qres);
  62. $this->last_qres = null;
  63. }
  64. sqlite3_close($this->db);
  65. }
  66. $this->db = null;
  67. }
  68. /**
  69. * check and activate db connection
  70. * @param string $action (active, kill, check) active by default
  71. * @return bool
  72. */
  73. function check_conn($action = ''){
  74. if(! $this->db){
  75. if($action !== 'active')
  76. return $action==='kill'?true:false;
  77. return $this->open()===false?false:true;
  78. }else{
  79. if($action==='kill'){
  80. $this->close();
  81. $this->db = null;
  82. }
  83. return true;
  84. }
  85. }
  86. /**
  87. * take a resource result set and return an array of type 'ASSOC','NUM','BOTH'
  88. * @param resource $result_set
  89. * @param string $result_type in 'ASSOC','NUM','BOTH'
  90. */
  91. function fetch_res($result_set,$result_type='ASSOC'){
  92. $result_type = strtoupper($result_type);
  93. if(! in_array($result_type,array('NUM','ASSOC','BOTH')) )
  94. $result_type = 'ASSOC';
  95. if($result_type==='ASSOC'){
  96. while($res[]=sqlite3_fetch_array($result_set));
  97. unset($res[count($res)-1]);//unset last empty row
  98. }elseif($result_type==='NUM'){
  99. while($res[]=sqlite3_fetch($result_set));
  100. unset($res[count($res)-1]);//unset last empty row
  101. }else{
  102. while($row=sqlite3_fetch_array($result_set)){
  103. $res[] = array_merge($row,array_values($row));
  104. };
  105. }
  106. if( empty($res) )
  107. return $this->last_q2a_res = false;
  108. $this->num_rows = count($res);
  109. return $this->last_q2a_res = $res;
  110. }
  111. function last_insert_id(){
  112. return $this->db?sqlite3_last_insert_rowid($this->db):FALSE;
  113. }
  114. /**
  115. * perform a query on the database
  116. * @param string $Q_str
  117. * @return result id or bool depend on the query type| FALSE
  118. */
  119. function query($Q_str){
  120. if(! $this->db ){
  121. if(! (db::$autoconnect && $this->open()) )
  122. return FALSE;
  123. }
  124. $this->verbose($Q_str,__FUNCTION__,2);
  125. if($this->last_qres){#- close unclosed previous qres
  126. sqlite3_query_close($this->last_qres);
  127. $this->last_qres = null;
  128. }
  129. if( preg_match('!^\s*select!i',$Q_str) ){
  130. $this->last_qres = sqlite3_query($this->db,$Q_str);
  131. $res = $this->last_qres;
  132. }else{
  133. $res = sqlite3_exec($this->db,$Q_str);
  134. }
  135. if(! $res)
  136. $this->set_error(__FUNCTION__);
  137. return $res;
  138. }
  139. /**
  140. * perform a query on the database like query but return the affected_rows instead of result
  141. * give a most suitable answer on query such as INSERT OR DELETE
  142. * Be aware that delete without where clause can return 0 even if several rows were deleted that's a sqlite bug!
  143. * i will add a workaround when i'll get some time! (use get_count before and after such query)
  144. * @param string $Q_str
  145. * @return int affected_rows
  146. */
  147. function query_affected_rows($Q_str){
  148. if(! $this->query($Q_str) )
  149. return FALSE;
  150. return sqlite3_changes($this->db);
  151. }
  152. /**
  153. * return the list of field in $table
  154. * @param string $table name of the sql table to work on
  155. * @param bool $extended_info if true will return the result of a show field query in a query_to_array fashion
  156. * (indexed by fieldname instead of int if false)
  157. * @return array
  158. */
  159. function list_table_fields($table,$extended_info=FALSE){
  160. # Try the simple method
  161. if( (! $extended_info) && $res = $this->query_to_array("SELECT * FROM $table LIMIT 0,1")){
  162. return array_keys($res[0]);
  163. }else{ # There 's no row in this table so we try an alternate method or we want extended infos
  164. if(! $fields = $this->query_to_array("SELECT sql FROM sqlite_master WHERE type='table' AND name ='$table'") )
  165. return FALSE;
  166. # get fields from the create query
  167. $flds_str = $fields[0]['sql'];
  168. $flds_str = substr($flds_str,strpos($flds_str,'('));
  169. $type = "((?:[a-z]+)\s*(?:\(\s*\d+\s*(?:,\s*\d+\s*)?\))?)?\s*";
  170. $default = '(?:DEFAULT\s+((["\']).*?(?<!\\\\)\\4|[^\s,]+))?\s*';
  171. if( preg_match_all('/(\w+)\s+'.$type.$default.'[^,]*(,|\))/i',$flds_str,$m,PREG_SET_ORDER) ){
  172. $key = "PRIMARY|UNIQUE|CHECK";
  173. $Extra = 'AUTOINCREMENT';
  174. $default = 'DEFAULT\s+((["\'])(.*?)(?<!\\\\)\\2|\S+)';
  175. foreach($m as $v){
  176. list($field,$name,$type,$default) = $v;
  177. # print_r($field);
  178. if(!$extended_info){
  179. $res[] = $name;
  180. continue;
  181. }
  182. $res[$name] = array('Field'=>$name,'Type'=>$type,'Null'=>'YES','Key'=>'','Default'=>$default,'Extra'=>'');
  183. if( preg_match("!($key)!i",$field,$n))
  184. $res[$name]['Key'] = $n[1];
  185. if( preg_match("!($Extra)!i",$field,$n))
  186. $res[$name]['Extra'] = $n[1];
  187. if( preg_match('!(NO)T\s+NULL!i',$field,$n))
  188. $res[$name]['Null'] = $n[1];
  189. }
  190. return $res;
  191. }
  192. return FALSE;
  193. }
  194. }
  195. /**
  196. * get the table list
  197. * @return array
  198. */
  199. function list_tables(){
  200. if(! $tables = $this->query_to_array('SELECT name FROM sqlite_master WHERE type=\'table\'') )
  201. return FALSE;
  202. foreach($tables as $v){
  203. $ret[] = $v['name'];
  204. }
  205. return $ret;
  206. }
  207. /** Verifier si cette methode peut s'appliquer a SQLite * /
  208. function show_table_keys($table){}
  209. /**
  210. * optimize table statement query
  211. * @param string $table name of the table to optimize
  212. * @return bool
  213. */
  214. function optimize($table){
  215. return $this->vacuum($table);
  216. }
  217. /**
  218. * sqlitedb specific method to use the vacuum statement (used as replacement for mysql optimize statements)
  219. * you should use db::optimize() method instead for better portability
  220. * @param string $table_or_index name of table or index to vacuum
  221. * @return bool
  222. */
  223. function vacuum($table_or_index){
  224. return $this->query("VACUUM $table_or_index;");
  225. }
  226. /**
  227. * base method you should replace this one in the extended class, to use the appropriate escape func regarding the database implementation
  228. * @param string $quotestyle (both/single/double) which type of quote to escape
  229. * @return str
  230. */
  231. function escape_string($string,$quotestyle='both'){
  232. if( function_exists('sqlite_escape_string') ){
  233. $string = sqlite_escape_string($string);
  234. $string = str_replace("''","'",$string); #- no quote escaped so will work like with no sqlite_escape_string available
  235. }else{
  236. $escapes = array("\x00", "\x0a", "\x0d", "\x1a", "\x09","\\");
  237. $replace = array('\0', '\n', '\r', '\Z' , '\t', "\\\\");
  238. }
  239. switch(strtolower($quotestyle)){
  240. case 'double':
  241. case 'd':
  242. case '"':
  243. $escapes[] = '"';
  244. $replace[] = '\"';
  245. break;
  246. case 'single':
  247. case 's':
  248. case "'":
  249. $escapes[] = "'";
  250. $replace[] = "''";
  251. break;
  252. case 'both':
  253. case 'b':
  254. case '"\'':
  255. case '\'"':
  256. $escapes[] = '"';
  257. $replace[] = '\"';
  258. $escapes[] = "'";
  259. $replace[] = "''";
  260. break;
  261. }
  262. return str_replace($escapes,$replace,$string);
  263. }
  264. function error_no(){
  265. $this->verbose('sqlite3 driver doesn\'t support this method',__function__,1);
  266. }
  267. function error_str($errno=null){
  268. return sqlite3_error($this->db);
  269. }
  270. protected function set_error($callingfunc=null){
  271. static $i=0;
  272. if(! $this->db ){
  273. $this->error[$i] = '[ERROR] No Db Handler';
  274. }else{
  275. $this->error[$i] = $this->error_str();
  276. }
  277. $this->last_error = $this->error[$i];
  278. $this->verbose($this->error[$i],$callingfunc,1);
  279. $i++;
  280. }
  281. }