15 |
15 |
16 $neutral_color = 'C'; |
16 $neutral_color = 'C'; |
17 |
17 |
18 function run_installer_stage($stage_id, $stage_name, $function, $failure_explanation, $allow_skip = true) |
18 function run_installer_stage($stage_id, $stage_name, $function, $failure_explanation, $allow_skip = true) |
19 { |
19 { |
20 static $resumed = false; |
20 static $resumed = false; |
21 static $resume_stack = array(); |
21 static $resume_stack = array(); |
22 |
22 |
23 if ( empty($resume_stack) && isset($_POST['resume_stack']) && preg_match('/[a-z_]+((\|[a-z_]+)+)/', $_POST['resume_stack']) ) |
23 if ( empty($resume_stack) && isset($_POST['resume_stack']) && preg_match('/[a-z_]+((\|[a-z_]+)+)/', $_POST['resume_stack']) ) |
24 { |
24 { |
25 $resume_stack = explode('|', $_POST['resume_stack']); |
25 $resume_stack = explode('|', $_POST['resume_stack']); |
26 } |
26 } |
27 |
27 |
28 $already_run = false; |
28 $already_run = false; |
29 if ( in_array($stage_id, $resume_stack) ) |
29 if ( in_array($stage_id, $resume_stack) ) |
30 { |
30 { |
31 $already_run = true; |
31 $already_run = true; |
32 } |
32 } |
33 |
33 |
34 if ( !$resumed ) |
34 if ( !$resumed ) |
35 { |
35 { |
36 if ( !isset($_GET['sub']) ) |
36 if ( !isset($_GET['sub']) ) |
37 $resumed = true; |
37 $resumed = true; |
38 if ( isset($_GET['sub']) && $_GET['sub'] == $stage_id ) |
38 if ( isset($_GET['sub']) && $_GET['sub'] == $stage_id ) |
39 { |
39 { |
40 $resumed = true; |
40 $resumed = true; |
41 } |
41 } |
42 } |
42 } |
43 if ( !$resumed && $allow_skip ) |
43 if ( !$resumed && $allow_skip ) |
44 { |
44 { |
45 echo_stage_success($stage_id, $stage_name); |
45 echo_stage_success($stage_id, $stage_name); |
46 return false; |
46 return false; |
47 } |
47 } |
48 if ( !function_exists($function) ) |
48 if ( !function_exists($function) ) |
49 die('libenanoinstall: CRITICAL: function "' . $function . '" for ' . $stage_id . ' doesn\'t exist'); |
49 die('libenanoinstall: CRITICAL: function "' . $function . '" for ' . $stage_id . ' doesn\'t exist'); |
50 $result = call_user_func($function, false, $already_run); |
50 $result = call_user_func($function, false, $already_run); |
51 if ( $result ) |
51 if ( $result ) |
52 { |
52 { |
53 echo_stage_success($stage_id, $stage_name); |
53 echo_stage_success($stage_id, $stage_name); |
54 $resume_stack[] = $stage_id; |
54 $resume_stack[] = $stage_id; |
55 return true; |
55 return true; |
56 } |
56 } |
57 else |
57 else |
58 { |
58 { |
59 echo_stage_failure($stage_id, $stage_name, $failure_explanation, $resume_stack); |
59 echo_stage_failure($stage_id, $stage_name, $failure_explanation, $resume_stack); |
60 return false; |
60 return false; |
61 } |
61 } |
62 } |
62 } |
63 |
63 |
64 function start_install_table() |
64 function start_install_table() |
65 { |
65 { |
66 echo '<table border="0" cellspacing="0" cellpadding="0" style="margin-top: 10px;">' . "\n"; |
66 echo '<table border="0" cellspacing="0" cellpadding="0" style="margin-top: 10px;">' . "\n"; |
67 } |
67 } |
68 |
68 |
69 function close_install_table() |
69 function close_install_table() |
70 { |
70 { |
71 echo '</table>' . "\n\n"; |
71 echo '</table>' . "\n\n"; |
72 flush(); |
72 flush(); |
73 } |
73 } |
74 |
74 |
75 function echo_stage_success($stage_id, $stage_name) |
75 function echo_stage_success($stage_id, $stage_name) |
76 { |
76 { |
77 global $neutral_color; |
77 global $neutral_color; |
78 $neutral_color = ( $neutral_color == 'A' ) ? 'C' : 'A'; |
78 $neutral_color = ( $neutral_color == 'A' ) ? 'C' : 'A'; |
79 echo '<tr><td style="width: 500px; background-color: #' . "{$neutral_color}{$neutral_color}FF{$neutral_color}{$neutral_color}" . '; padding: 0 5px;">' . htmlspecialchars($stage_name) . '</td><td style="padding: 0 5px;"><img alt="Done" src="../images/check.png" /></td></tr>' . "\n"; |
79 echo '<tr><td style="width: 500px; background-color: #' . "{$neutral_color}{$neutral_color}FF{$neutral_color}{$neutral_color}" . '; padding: 0 5px;">' . htmlspecialchars($stage_name) . '</td><td style="padding: 0 5px;"><img alt="Done" src="../images/check.png" /></td></tr>' . "\n"; |
80 flush(); |
80 flush(); |
81 } |
81 } |
82 |
82 |
83 function echo_stage_failure($stage_id, $stage_name, $failure_explanation, $resume_stack) |
83 function echo_stage_failure($stage_id, $stage_name, $failure_explanation, $resume_stack) |
84 { |
84 { |
85 global $neutral_color; |
85 global $neutral_color; |
86 global $lang; |
86 global $lang; |
87 |
87 |
88 $neutral_color = ( $neutral_color == 'A' ) ? 'C' : 'A'; |
88 $neutral_color = ( $neutral_color == 'A' ) ? 'C' : 'A'; |
89 echo '<tr><td style="width: 500px; background-color: #' . "FF{$neutral_color}{$neutral_color}{$neutral_color}{$neutral_color}" . '; padding: 0 5px;">' . htmlspecialchars($stage_name) . '</td><td style="padding: 0 5px;"><img alt="Failed" src="../images/checkbad.png" /></td></tr>' . "\n"; |
89 echo '<tr><td style="width: 500px; background-color: #' . "FF{$neutral_color}{$neutral_color}{$neutral_color}{$neutral_color}" . '; padding: 0 5px;">' . htmlspecialchars($stage_name) . '</td><td style="padding: 0 5px;"><img alt="Failed" src="../images/checkbad.png" /></td></tr>' . "\n"; |
90 flush(); |
90 flush(); |
91 close_install_table(); |
91 close_install_table(); |
92 $post_data = ''; |
92 $post_data = ''; |
93 $mysql_error = mysql_error(); |
93 $mysql_error = mysql_error(); |
94 $file = ( defined('IN_ENANO_UPGRADE') ) ? 'upgrade.php' : 'install.php'; |
94 $file = ( defined('IN_ENANO_UPGRADE') ) ? 'upgrade.php' : 'install.php'; |
95 foreach ( $_POST as $key => $value ) |
95 foreach ( $_POST as $key => $value ) |
96 { |
96 { |
97 // FIXME: These should really also be sanitized for double quotes |
97 // FIXME: These should really also be sanitized for double quotes |
98 $value = htmlspecialchars($value); |
98 $value = htmlspecialchars($value); |
99 $key = htmlspecialchars($key); |
99 $key = htmlspecialchars($key); |
100 $post_data .= " <input type=\"hidden\" name=\"$key\" value=\"$value\" />\n"; |
100 $post_data .= " <input type=\"hidden\" name=\"$key\" value=\"$value\" />\n"; |
101 } |
101 } |
102 if ( $stage_id == 'renameconfig' ) |
102 if ( $stage_id == 'renameconfig' ) |
103 echo '<p>' . $failure_explanation . '</p>'; |
103 echo '<p>' . $failure_explanation . '</p>'; |
104 else |
104 else |
105 echo '<form action="' . $file . '?stage=install&sub=' . $stage_id . '" method="post"> |
105 echo '<form action="' . $file . '?stage=install&sub=' . $stage_id . '" method="post"> |
106 ' . $post_data . ' |
106 ' . $post_data . ' |
107 <input type="hidden" name="resume_stack" value="' . htmlspecialchars(implode('|', $resume_stack)) . '" /> |
107 <input type="hidden" name="resume_stack" value="' . htmlspecialchars(implode('|', $resume_stack)) . '" /> |
108 <h3>' . $lang->get('meta_msg_err_stagefailed_title') . '</h3> |
108 <h3>' . $lang->get('meta_msg_err_stagefailed_title') . '</h3> |
109 <p>' . $failure_explanation . '</p> |
109 <p>' . $failure_explanation . '</p> |
110 ' . ( !empty($mysql_error) ? "<p>" . $lang->get('meta_msg_err_stagefailed_mysqlerror') . " $mysql_error</p>" : '' ) . ' |
110 ' . ( !empty($mysql_error) ? "<p>" . $lang->get('meta_msg_err_stagefailed_mysqlerror') . " $mysql_error</p>" : '' ) . ' |
111 <p>' . $lang->get('meta_msg_err_stagefailed_body') . '</p> |
111 <p>' . $lang->get('meta_msg_err_stagefailed_body') . '</p> |
112 <p style="text-align: center;"><input type="submit" value="' . $lang->get('meta_btn_retry_installation') . '" /></p> |
112 <p style="text-align: center;"><input type="submit" value="' . $lang->get('meta_btn_retry_installation') . '" /></p> |
113 </form>'; |
113 </form>'; |
114 global $ui; |
114 global $ui; |
115 $ui->show_footer(); |
115 $ui->show_footer(); |
116 exit; |
116 exit; |
117 } |
117 } |
118 |
118 |
119 function enano_perform_upgrade($target_branch) |
119 function enano_perform_upgrade($target_branch) |
120 { |
120 { |
121 global $db, $session, $paths, $template, $plugins; // Common objects |
121 global $db, $session, $paths, $template, $plugins; // Common objects |
122 // Import version info |
122 // Import version info |
123 global $enano_versions; |
123 global $enano_versions; |
124 // Import UI functions |
124 // Import UI functions |
125 global $ui; |
125 global $ui; |
126 // This is needed for upgrade abstraction |
126 // This is needed for upgrade abstraction |
127 global $dbdriver; |
127 global $dbdriver; |
128 |
128 |
129 // see if we're actually supposed to be in post-upgrade |
129 // see if we're actually supposed to be in post-upgrade |
130 if ( getConfig('enano_version') == 'upg-' . installer_enano_version() ) |
130 if ( getConfig('enano_version') == 'upg-' . installer_enano_version() ) |
131 { |
131 { |
132 // yep, fall out here to avoid errors |
132 // yep, fall out here to avoid errors |
133 return true; |
133 return true; |
134 } |
134 } |
135 |
135 |
136 // Main upgrade stage |
136 // Main upgrade stage |
137 |
137 |
138 // Init vars |
138 // Init vars |
139 list($major_version, $minor_version) = explode('.', installer_enano_version()); |
139 list($major_version, $minor_version) = explode('.', installer_enano_version()); |
140 $installer_branch = "$major_version.$minor_version"; |
140 $installer_branch = "$major_version.$minor_version"; |
141 $installer_branch = preg_replace('/^upg-/', '', $installer_branch); |
141 $installer_branch = preg_replace('/^upg-/', '', $installer_branch); |
142 $target_branch = preg_replace('/^upg-/', '', $target_branch); |
142 $target_branch = preg_replace('/^upg-/', '', $target_branch); |
143 |
143 |
144 $version_flipped = array_flip($enano_versions[$target_branch]); |
144 $version_flipped = array_flip($enano_versions[$target_branch]); |
145 $version_curr = enano_version(); |
145 $version_curr = enano_version(); |
146 // Change this to be the last version in the current branch. |
146 // Change this to be the last version in the current branch. |
147 // If we're just upgrading within this branch, use the version the installer library |
147 // If we're just upgrading within this branch, use the version the installer library |
148 // reports to us. Else, use the latest in the old (current target) branch. |
148 // reports to us. Else, use the latest in the old (current target) branch. |
149 // $version_target = installer_enano_version(); |
149 // $version_target = installer_enano_version(); |
150 $version_target = ( $target_branch === $installer_branch ) ? installer_enano_version() : $enano_versions[$target_branch][ count($enano_versions[$target_branch]) - 1 ]; |
150 $version_target = ( $target_branch === $installer_branch ) ? installer_enano_version() : $enano_versions[$target_branch][ count($enano_versions[$target_branch]) - 1 ]; |
151 |
151 |
152 // Calculate which scripts to run |
152 // Calculate which scripts to run |
153 if ( !isset($version_flipped[$version_curr]) ) |
153 if ( !isset($version_flipped[$version_curr]) ) |
154 { |
154 { |
155 echo '<p>ERROR: Unsupported version</p>'; |
155 echo '<p>ERROR: Unsupported version</p>'; |
156 $ui->show_footer(); |
156 $ui->show_footer(); |
157 exit; |
157 exit; |
158 } |
158 } |
159 if ( !isset($version_flipped[$version_target]) ) |
159 if ( !isset($version_flipped[$version_target]) ) |
160 { |
160 { |
161 echo '<p>ERROR: Upgrader doesn\'t support its own version</p>'; |
161 echo '<p>ERROR: Upgrader doesn\'t support its own version</p>'; |
162 $ui->show_footer(); |
162 $ui->show_footer(); |
163 exit; |
163 exit; |
164 } |
164 } |
165 $upg_queue = array(); |
165 $upg_queue = array(); |
166 for ( $i = $version_flipped[$version_curr]; $i < $version_flipped[$version_target]; $i++ ) |
166 for ( $i = $version_flipped[$version_curr]; $i < $version_flipped[$version_target]; $i++ ) |
167 { |
167 { |
168 if ( !isset($enano_versions[$target_branch][$i + 1]) ) |
168 if ( !isset($enano_versions[$target_branch][$i + 1]) ) |
169 { |
169 { |
170 echo '<p>ERROR: Unsupported intermediate version</p>'; |
170 echo '<p>ERROR: Unsupported intermediate version</p>'; |
171 $ui->show_footer(); |
171 $ui->show_footer(); |
172 exit; |
172 exit; |
173 } |
173 } |
174 $ver_this = $enano_versions[$target_branch][$i]; |
174 $ver_this = $enano_versions[$target_branch][$i]; |
175 $ver_next = $enano_versions[$target_branch][$i + 1]; |
175 $ver_next = $enano_versions[$target_branch][$i + 1]; |
176 $upg_queue[] = array($ver_this, $ver_next); |
176 $upg_queue[] = array($ver_this, $ver_next); |
177 } |
177 } |
178 |
178 |
179 // Verify that all upgrade scripts are usable |
179 // Verify that all upgrade scripts are usable |
180 foreach ( $upg_queue as $verset ) |
180 foreach ( $upg_queue as $verset ) |
181 { |
181 { |
182 $file = ENANO_ROOT . "/install/schemas/upgrade/{$verset[0]}-{$verset[1]}-$dbdriver.sql"; |
182 $file = ENANO_ROOT . "/install/schemas/upgrade/{$verset[0]}-{$verset[1]}-$dbdriver.sql"; |
183 if ( !file_exists($file) ) |
183 if ( !file_exists($file) ) |
184 { |
184 { |
185 echo "<p>ERROR: Couldn't find required schema file: $file</p>"; |
185 echo "<p>ERROR: Couldn't find required schema file: $file</p>"; |
186 $ui->show_footer(); |
186 $ui->show_footer(); |
187 exit; |
187 exit; |
188 } |
188 } |
189 } |
189 } |
190 // Perform upgrade |
190 // Perform upgrade |
191 foreach ( $upg_queue as $verset ) |
191 foreach ( $upg_queue as $verset ) |
192 { |
192 { |
193 $file = ENANO_ROOT . "/install/schemas/upgrade/{$verset[0]}-{$verset[1]}-$dbdriver.sql"; |
193 $file = ENANO_ROOT . "/install/schemas/upgrade/{$verset[0]}-{$verset[1]}-$dbdriver.sql"; |
194 try |
194 try |
195 { |
195 { |
196 $parser = new SQL_Parser($file); |
196 $parser = new SQL_Parser($file); |
197 } |
197 } |
198 catch(Exception $e) |
198 catch(Exception $e) |
199 { |
199 { |
200 die("<pre>$e</pre>"); |
200 die("<pre>$e</pre>"); |
201 } |
201 } |
202 |
202 |
203 $parser->assign_vars(array( |
203 $parser->assign_vars(array( |
204 'TABLE_PREFIX' => table_prefix |
204 'TABLE_PREFIX' => table_prefix |
205 )); |
205 )); |
206 |
206 |
207 $sql_list = $parser->parse(); |
207 $sql_list = $parser->parse(); |
208 // Check for empty schema file |
208 // Check for empty schema file |
209 if ( $sql_list[0] === ';' && count($sql_list) == 1 ) |
209 if ( $sql_list[0] === ';' && count($sql_list) == 1 ) |
210 { |
210 { |
211 // It's empty, report success for this version |
211 // It's empty, report success for this version |
212 // See below for explanation of why setConfig() is called here |
212 // See below for explanation of why setConfig() is called here |
213 setConfig('enano_version', $verset[1]); |
213 setConfig('enano_version', $verset[1]); |
214 continue; |
214 continue; |
215 } |
215 } |
216 |
216 |
217 foreach ( $sql_list as $sql ) |
217 foreach ( $sql_list as $sql ) |
218 { |
218 { |
219 // check for '@' operator on query |
219 // check for '@' operator on query |
220 if ( substr($sql, 0, 1) == '@' ) |
220 if ( substr($sql, 0, 1) == '@' ) |
221 { |
221 { |
222 // Yes - perform query but don't check for errors |
222 // Yes - perform query but don't check for errors |
223 $db->sql_query($sql); |
223 $db->sql_query($sql); |
224 } |
224 } |
225 else |
225 else |
226 { |
226 { |
227 // Perform as normal |
227 // Perform as normal |
228 if ( !$db->sql_query($sql) ) |
228 if ( !$db->sql_query($sql) ) |
229 $db->_die(); |
229 $db->_die(); |
230 } |
230 } |
231 } |
231 } |
232 |
232 |
233 // Is there an additional script (logic) to be run after the schema? |
233 // Is there an additional script (logic) to be run after the schema? |
234 $postscript = ENANO_ROOT . "/install/schemas/upgrade/{$verset[0]}-{$verset[1]}.php"; |
234 $postscript = ENANO_ROOT . "/install/schemas/upgrade/{$verset[0]}-{$verset[1]}.php"; |
235 if ( file_exists($postscript) ) |
235 if ( file_exists($postscript) ) |
236 @include($postscript); |
236 @include($postscript); |
237 |
237 |
238 // The advantage of calling setConfig on the system version here? |
238 // The advantage of calling setConfig on the system version here? |
239 // Simple. If the upgrade fails, it will pick up from the last |
239 // Simple. If the upgrade fails, it will pick up from the last |
240 // version, not try to start again from the beginning. This will |
240 // version, not try to start again from the beginning. This will |
241 // still cause errors in most cases though. Eventually we probably |
241 // still cause errors in most cases though. Eventually we probably |
242 // need some sort of query-numbering system that tracks in-progress |
242 // need some sort of query-numbering system that tracks in-progress |
243 // upgrades. |
243 // upgrades. |
244 |
244 |
245 setConfig('enano_version', $verset[1]); |
245 setConfig('enano_version', $verset[1]); |
246 } |
246 } |
247 } |
247 } |
248 |
248 |