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