Newer
Older
backup-commander / install / apply-patches.php
  1. <?php
  2.  
  3. /**
  4. * SQL files must have a semi-colon at the end of each SQL statement
  5. *
  6. * PHP files can also be used as a patch but are optional
  7. *
  8. * The SQL file for a given patch number is applied before the PHP file
  9. *
  10. * If the PHP file bombs out, then there will be no way to recover. This can be seen in the PARAMS table where
  11. * db_apply_patch_php is the number of the patch which failed.
  12. *
  13. */
  14. $g_database_path = '../html/data/data.db';
  15. $g_patch_dir = 'db';
  16.  
  17. apply_patches();
  18. function apply_patches(){
  19.  
  20. global $g_database_path;
  21. //clear any previous php errors
  22. $db = new SQLite3( $g_database_path );
  23. $db->exec("delete from PARAMS where P_Name='db_apply_patch_php'");
  24.  
  25. //which patch to start with
  26. $curr_version = get_curr_patch_ver( );
  27. $st_patch_val = $curr_version;
  28. print( "Current version is $curr_version\n" );
  29. do{
  30. $st_patch_val++;
  31. //process the SQL patch first
  32. $patch_name = get_patch_name( $st_patch_val );
  33. $patch_data = read_patch( $patch_name );
  34. if($patch_data!=null){
  35. apply_patch_sql( $st_patch_val, $patch_name, $patch_data );
  36. }
  37. //process the PHP patch
  38. $patch_name = get_patch_name( $st_patch_val, "php");
  39. $patch_data = read_patch( $patch_name );
  40. if($patch_data!=null){
  41. apply_patch_php( $st_patch_val, $patch_name, $patch_data );
  42. }
  43. }while($patch_data!=null);
  44. $applied = $st_patch_val - $curr_version -1;
  45. print( "Applied $applied patches\n" );
  46.  
  47.  
  48. }
  49.  
  50. function apply_patch_php( $st_patch_val, $patch_name, $patch_data ){
  51. print("Applying patch: $patch_name \n");
  52. global $g_database_path;
  53. //first mark the database so that we know a patch has started
  54. $db = new SQLite3( $g_database_path );
  55. $db->exec("insert into PARAMS(P_Name, P_Value) values('db_apply_patch_php', $st_patch_val )");
  56. try{
  57. eval($patch_data);
  58. $db->exec("delete from PARAMS where P_Name='db_apply_patch_php'");
  59. }catch( Exception $e ){
  60. print( "Exception: " . $e->getMessage() );
  61. throw $e;
  62. }
  63. }
  64.  
  65.  
  66. function apply_patch_sql( $st_patch_val, $patch_name, $patch_data ){
  67.  
  68. print("Applying patch: $patch_name \n");
  69.  
  70. $arr_sql_stat = split_sql_data( $patch_data );
  71. if( count($arr_sql_stat) == 0){
  72. print("Patch empty\n");
  73. return;
  74. }
  75. global $g_database_path;
  76. //first mark the database so that we know a patch has started
  77. $db = new SQLite3( $g_database_path );
  78. $db->exec("insert into PARAMS(P_Name, P_Value) values('db_apply_patch', $st_patch_val )");
  79. try{
  80. for( $i=0; $i<count($arr_sql_stat); $i++ ){
  81. $db->exec( $arr_sql_stat[$i] );
  82. }
  83.  
  84. // update the version
  85. $db->exec("delete from PARAMS where P_Name='db_apply_patch'");
  86. $db->exec("update PARAMS set P_Value=$st_patch_val where P_Name='db_curr_patch'");
  87. }catch( Exception $e ){
  88. print( "Exception: " . $e->getMessage() );
  89. throw $e;
  90. }
  91.  
  92. }
  93.  
  94. /**
  95. * Simple return the patch contents as a string.
  96. *
  97. * Returns null if no such patch exists.
  98. *
  99. */
  100. function read_patch( $patch_name ){
  101. global $g_patch_dir;
  102. $fn = $g_patch_dir."/$patch_name";
  103. if(!file_exists($fn)) return null;
  104. return file_get_contents($fn);
  105. }
  106.  
  107. /**
  108. * Get the file name of the patch given it's integer number.
  109. *
  110. */
  111. function get_patch_name( $patch_int, $patch_type="sql"){
  112. return "p-$patch_int.$patch_type";
  113. }
  114.  
  115. /**
  116. * Read the database patch version from the params table.
  117. * Will create the table if it does not exists thus assuming that this the first run, setting db_curr_patch=0
  118. */
  119. function get_curr_patch_ver( ){
  120.  
  121. global $g_database_path;
  122. $db = new SQLite3( $g_database_path );
  123. $results = $db->query("SELECT name FROM sqlite_master WHERE type='table' AND name='PARAMS'");
  124. $row = $results->fetchArray();
  125. if( !$row ) {
  126. //create the table and the the version number
  127. print "Creating table PARAMS\n";
  128. $db->exec("CREATE TABLE \"PARAMS\" ( \"P_Name\" TEXT NOT NULL UNIQUE, \"P_Value\" TEXT, PRIMARY KEY(\"P_Name\"))");
  129. $db->exec("insert into PARAMS(P_Name, P_Value) values('db_curr_patch', 0 )");
  130. return 0;
  131. }
  132.  
  133. //read the version number
  134. $results = $db->query("SELECT P_Value FROM PARAMS WHERE P_Name='db_curr_patch'");
  135. $row = $results->fetchArray();
  136. if( !$row ) {
  137. print "Param db_curr_patch not found\n";
  138. exit(1);
  139. }
  140. return $row['P_Value'];
  141. }
  142.  
  143. /**
  144. * Return an array of strings, one for each SQL statement. Comments are ignored.
  145. */
  146. function split_sql_data( $patch_data ){
  147. $arr_sql_stat = array();
  148. $lines = preg_split("/\r\n|\n|\r/", $patch_data);
  149. $stat_nxt = '';
  150. $i=0;
  151. while( $i<count($lines) ){
  152. if( str_starts_with( trim($lines[$i]), '--') ) { $i++; continue; }
  153. $stat_nxt .= trim($lines[$i]);
  154. if( str_ends_with( trim($lines[$i]), ';') ) {
  155. array_push( $arr_sql_stat, $stat_nxt );
  156. $stat_nxt = '';
  157. }
  158. $i++;
  159. }
  160. return $arr_sql_stat;
  161. }
  162.  
  163.  
  164. ?>