Version Description
Download this release
Release Info
Developer | jcpeden |
Plugin | Backup and Restore WordPress – WPBackItUp Backup Plugin |
Version | 1.0.7 |
Comparing to | |
See all releases |
Code changes from version 1.0.6 to 1.0.7
- backups/status.log +1 -1
- includes/admin_page.php +1 -1
- includes/functions.php +63 -0
- includes/restore.php +312 -0
- js/ajaxfileupload.js +201 -0
- js/wp-backitup.js +21 -0
- readme.txt +23 -22
- screenshots/screenshot-1.png +0 -0
- screenshots/screenshot-2.png +0 -0
- screenshots/screenshot-3.png +0 -0
- wp-backitup.php +2 -2
backups/status.log
CHANGED
@@ -1 +1 @@
|
|
1 |
-
<ul><li>Creating backup directory...Done!</li><li>Backing up your files...Done!</li><li>Backing up your database...Done!</li><li>Creating backup zip...Done!</li><li>
|
1 |
+
<ul><li>Creating backup directory...Done!</li><li>Backing up your files...Done!</li><li>Backing up your database...Done!</li><li>Creating backup zip...Done!</li><li>Export file created successfully. You can download your export file using the link above.</li></ul>
|
includes/admin_page.php
CHANGED
@@ -1 +1 @@
|
|
1 |
-
<?php
|
1 |
+
<?php
|
includes/functions.php
CHANGED
@@ -110,4 +110,67 @@ if(!function_exists('recursive_delete')){
|
|
110 |
}
|
111 |
return true;
|
112 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
}
|
110 |
}
|
111 |
return true;
|
112 |
}
|
113 |
+
}
|
114 |
+
|
115 |
+
//defube db_import function
|
116 |
+
if(!function_exists('db_import')) {
|
117 |
+
function db_import($restoration_dir_path, $import_siteurl, $current_siteurl, $table_prefix, $import_table_prefix, $dbc) {
|
118 |
+
global $wpdb;
|
119 |
+
$sql_files = glob($restoration_dir_path . "/*.sql");
|
120 |
+
foreach($sql_files as $sql_file) {
|
121 |
+
$templine = ''; // Temporary variable, used to store current query
|
122 |
+
$lines = file($sql_file); // Read in entire file
|
123 |
+
foreach ($lines as $line) { // Loop through each line
|
124 |
+
if (substr($line, 0, 2) == '--' || $line == '') continue; // Skip it if it's a comment
|
125 |
+
$templine .= $line; // Add this line to the current segment
|
126 |
+
if (substr(trim($line), -1, 1) == ';') { // If it has a semicolon at the end, it's the end of the query
|
127 |
+
//replace imported site url with current site url
|
128 |
+
if( strstr( trim($templine), trim($import_siteurl) ) == TRUE ) //If import site url is found
|
129 |
+
$templine = str_replace( trim($import_siteurl), trim($current_siteurl), $templine ); // Replace import site url with current site url
|
130 |
+
//if the table prefixes are different, replace the imported site prefixes with the current prefixes
|
131 |
+
if ($table_prefix != $import_table_prefix) {
|
132 |
+
if( strstr( trim($templine), trim($import_table_prefix) ) == TRUE ) //If import table prefix is found
|
133 |
+
$templine = str_replace( trim($import_table_prefix), trim($table_prefix), $templine ); // Replace import site table prefix with current site table prefix
|
134 |
+
}
|
135 |
+
// Perform the query
|
136 |
+
if( mysqli_query($dbc, $templine) === FALSE)
|
137 |
+
print('Error performing query \'<strong>' . $templine . '\': ' . mysql_error() . '<br /><br />');
|
138 |
+
$templine = ''; // Reset temp variable to empty
|
139 |
+
}
|
140 |
+
}
|
141 |
+
}
|
142 |
+
return true;
|
143 |
+
}
|
144 |
+
}
|
145 |
+
|
146 |
+
//Define zip function
|
147 |
+
function zip($source, $destination, $ignore) {
|
148 |
+
if (is_string($source)) $source_arr = array($source); // convert it to array
|
149 |
+
if (!extension_loaded('zip')) {
|
150 |
+
return false;
|
151 |
+
}
|
152 |
+
$zip = new ZipArchive();
|
153 |
+
if (!$zip->open($destination, ZIPARCHIVE::CREATE)) {
|
154 |
+
return false;
|
155 |
+
}
|
156 |
+
foreach ($source_arr as $source) {
|
157 |
+
if (!file_exists($source)) continue;
|
158 |
+
$source = str_replace('\\', '/', realpath($source));
|
159 |
+
if (is_dir($source) === true) {
|
160 |
+
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);
|
161 |
+
foreach ($files as $file) {
|
162 |
+
if (!preg_match($ignore, $file)) {
|
163 |
+
$file = str_replace('\\', '/', realpath($file));
|
164 |
+
if (is_dir($file) === true) {
|
165 |
+
$zip->addEmptyDir(str_replace($source . '/', '', $file . '/'));
|
166 |
+
} else if (is_file($file) === true) {
|
167 |
+
$zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file));
|
168 |
+
}
|
169 |
+
}
|
170 |
+
}
|
171 |
+
} else if (is_file($source) === true) {
|
172 |
+
$zip->addFromString(basename($source), file_get_contents($source));
|
173 |
+
}
|
174 |
+
}
|
175 |
+
return $zip->close();
|
176 |
}
|
includes/restore.php
ADDED
@@ -0,0 +1,312 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
//define constants
|
3 |
+
define("WP_BACKITUP_DIRNAME", basename(dirname(dirname(__FILE__))) );
|
4 |
+
define("BACKUP_PATH", dirname(dirname(__FILE__)) .'/backups/' );
|
5 |
+
define('WP_CONTENT_PATH', dirname(dirname(dirname(dirname(__FILE__)))));
|
6 |
+
|
7 |
+
//create log file
|
8 |
+
$log = BACKUP_PATH . "status.log";
|
9 |
+
$fh = fopen($log, 'w') or die("can't open file");
|
10 |
+
fwrite($fh, '<ul>');
|
11 |
+
|
12 |
+
//include functions
|
13 |
+
require('functions.php');
|
14 |
+
|
15 |
+
// 5 minutes per image should be PLENTY
|
16 |
+
@set_time_limit(900);
|
17 |
+
|
18 |
+
|
19 |
+
//Delete any zips in the upload directory first
|
20 |
+
foreach (glob(BACKUP_PATH .'*.zip') as $file) {
|
21 |
+
unlink($file);
|
22 |
+
}
|
23 |
+
|
24 |
+
//Move the uploaded zip to the plugin directory
|
25 |
+
fwrite($fh, "<li>Uploading restoration file...");
|
26 |
+
$restore_file_name = basename( $_FILES['wpbackitup-zip']['name']);
|
27 |
+
$restore_path = BACKUP_PATH . $restore_file_name;
|
28 |
+
if(move_uploaded_file($_FILES['wpbackitup-zip']['tmp_name'], $restore_path)) {
|
29 |
+
fwrite($fh, "Done!</li>");
|
30 |
+
} else {
|
31 |
+
fwrite($fh, "</li><li class=\"error\">Your file could not be uploaded.</li></ul>");
|
32 |
+
recursive_delete($restoration_dir_path);
|
33 |
+
unlink(BACKUP_PATH . $restore_file_name);
|
34 |
+
fclose($fh);
|
35 |
+
die();
|
36 |
+
|
37 |
+
}
|
38 |
+
|
39 |
+
//Unzip the uploaded restore file
|
40 |
+
fwrite($fh, "<li>Unzipping...");
|
41 |
+
$zip = new ZipArchive;
|
42 |
+
$res = $zip->open(BACKUP_PATH . $restore_file_name);
|
43 |
+
if ($res === TRUE) {
|
44 |
+
$zip->extractTo(BACKUP_PATH);
|
45 |
+
$zip->close();
|
46 |
+
fwrite($fh, "Done!</li>");
|
47 |
+
} else {
|
48 |
+
fwrite($fh, "</li><li class=\"error\">Your restoration file could not be unzipped.</li></ul>");
|
49 |
+
recursive_delete($restoration_dir_path);
|
50 |
+
unlink(BACKUP_PATH . $restore_file_name);
|
51 |
+
fclose($fh);
|
52 |
+
die();
|
53 |
+
}
|
54 |
+
|
55 |
+
//Identify the restoration directory
|
56 |
+
fwrite($fh, "<li>Validating zip...");
|
57 |
+
if(count(glob(BACKUP_PATH . "*", GLOB_ONLYDIR)) == 1) { //does this need wilcard?
|
58 |
+
foreach(glob(BACKUP_PATH . "*", GLOB_ONLYDIR) as $dir) { //does this need wilcard?
|
59 |
+
$restoration_dir_path = $dir;
|
60 |
+
}
|
61 |
+
}
|
62 |
+
if(glob($restoration_dir_path .'/backupsiteinfo.txt') ){
|
63 |
+
fwrite($fh, "Done!</li>");
|
64 |
+
} else {
|
65 |
+
fwrite($fh, "</li><li class=\"error\">Your zip file does not contain backupsiteinfo.txt. Please choose another file.</li></ul>");
|
66 |
+
recursive_delete($restoration_dir_path);
|
67 |
+
unlink(BACKUP_PATH . $restore_file_name);
|
68 |
+
fclose($fh);
|
69 |
+
die();
|
70 |
+
}
|
71 |
+
|
72 |
+
//If themes dir is present, restore it to wp-content
|
73 |
+
if(glob($restoration_dir_path . "/themes")) {
|
74 |
+
fwrite($fh, "<li>Restoring themes...");
|
75 |
+
$themes_dir = WP_CONTENT_PATH .'/themes';
|
76 |
+
if(!recursive_delete($themes_dir)) {
|
77 |
+
fwrite($fh, "</li><li class=\"error\">Unable to remove existing themes directory for import. Please check your CHMOD settings in /wp-content/themes.</li></ul>");
|
78 |
+
recursive_delete($restoration_dir_path);
|
79 |
+
unlink(BACKUP_PATH . $restore_file_name);
|
80 |
+
fclose($fh);
|
81 |
+
die();
|
82 |
+
}
|
83 |
+
if(!create_dir($themes_dir)) {
|
84 |
+
fwrite($fh, "</li><li class=\"error\">Unable to create new themes directory for import. Please check your CHMOD settings in /wp-content/themes.</li></ul>");
|
85 |
+
recursive_delete($restoration_dir_path);
|
86 |
+
unlink(BACKUP_PATH . $restore_file_name);
|
87 |
+
fclose($fh);
|
88 |
+
die();
|
89 |
+
}
|
90 |
+
if(recusive_copy($restoration_dir_path .'/themes', $themes_dir, array( 'cgi-bin', '.', '..','._', $restore_file_name )) ) {
|
91 |
+
fwrite($fh, "Done!</li>");
|
92 |
+
} else {
|
93 |
+
fwrite($fh, "</li><li class=\"error\">Unable to import themes. Please try again.</li></ul>");
|
94 |
+
recursive_delete($restoration_dir_path);
|
95 |
+
unlink(BACKUP_PATH . $restore_file_name);
|
96 |
+
fclose($fh);
|
97 |
+
die();
|
98 |
+
}
|
99 |
+
} else {
|
100 |
+
fwrite($fh, "<li class=\"error\">Warning: Themes directory not detected in import file.</li>");
|
101 |
+
}
|
102 |
+
|
103 |
+
//If uploads dir is present, restore it to wp-content
|
104 |
+
if(glob($restoration_dir_path . "/uploads")) {
|
105 |
+
fwrite($fh, "<li>Restoring uploads...");
|
106 |
+
$uploads_dir = WP_CONTENT_PATH .'/uploads';
|
107 |
+
if(!recursive_delete($uploads_dir) ){
|
108 |
+
fwrite($fh, "</li><li class=\"error\">Unable to create new uploads directory for import. Please check your CHMOD settings in /wp-content/uploads.</li></ul>");
|
109 |
+
recursive_delete($restoration_dir_path);
|
110 |
+
unlink(BACKUP_PATH . $restore_file_name);
|
111 |
+
fclose($fh);
|
112 |
+
die();
|
113 |
+
}
|
114 |
+
if(!create_dir($uploads_dir) ) {
|
115 |
+
fwrite($fh, "</li><li class=\"error\">Unable to create new uploads directory for import. Please check your CHMOD settings in /wp-content/uploads.</li></ul>");
|
116 |
+
recursive_delete($restoration_dir_path);
|
117 |
+
unlink(BACKUP_PATH . $restore_file_name);
|
118 |
+
fclose($fh);
|
119 |
+
die();
|
120 |
+
}
|
121 |
+
if (recusive_copy($restoration_dir_path .'/uploads', $uploads_dir, array( 'cgi-bin', '.', '..','._', $restore_file_name )) ) {
|
122 |
+
fwrite($fh, "Done!</li>");
|
123 |
+
} else {
|
124 |
+
fwrite($fh, "</li><li class=\"error\">Unable to import uploads. Please try again.</li></ul>");
|
125 |
+
recursive_delete($restoration_dir_path);
|
126 |
+
unlink(BACKUP_PATH . $restore_file_name);
|
127 |
+
fclose($fh);
|
128 |
+
die();
|
129 |
+
}
|
130 |
+
} else {
|
131 |
+
fwrite($fh, "<li class=\"error\">Warning: Uploads directory not detected in import file.</li>");
|
132 |
+
}
|
133 |
+
|
134 |
+
//If plugins dir is present, restore it to wp-content (exclude wp-backitup)
|
135 |
+
if(glob($restoration_dir_path . "/plugins")) {
|
136 |
+
fwrite($fh, "<li>Restoring plugins...");
|
137 |
+
$plugins_dir = WP_CONTENT_PATH .'/plugins';
|
138 |
+
if(!recursive_delete($plugins_dir, array('cgi-bin','.','..','._', WP_BACKITUP_DIRNAME) ) ) {
|
139 |
+
fwrite($fh, "</li><li class=\"error\">Unable to create new plugins directory for import. Please check your CHMOD settings in /wp-content/plugins.</li></ul>");
|
140 |
+
recursive_delete($restoration_dir_path);
|
141 |
+
unlink(BACKUP_PATH . $restore_file_name);
|
142 |
+
fclose($fh);
|
143 |
+
die();
|
144 |
+
}
|
145 |
+
if(!create_dir($plugins_dir) ){
|
146 |
+
fwrite($fh, "</li><li class=\"error\">Unable to create new plugins directory for import. Please check your CHMOD settings in /wp-content/plugins.</li></ul>");
|
147 |
+
recursive_delete($restoration_dir_path);
|
148 |
+
unlink(BACKUP_PATH . $restore_file_name);
|
149 |
+
fclose($fh);
|
150 |
+
die();
|
151 |
+
}
|
152 |
+
if( recusive_copy($restoration_dir_path .'/plugins', $plugins_dir, array( 'cgi-bin', '.', '..','._', $restore_file_name )) ) {
|
153 |
+
fwrite($fh, "Done!</li>");
|
154 |
+
} else {
|
155 |
+
fwrite($fh, "</li><li class=\"error\">Unable to import plugins. Please try again.</li></ul>");
|
156 |
+
recursive_delete($restoration_dir_path);
|
157 |
+
unlink(BACKUP_PATH . $restore_file_name);
|
158 |
+
fclose($fh);
|
159 |
+
die();
|
160 |
+
}
|
161 |
+
} else {
|
162 |
+
fwrite($fh, "<li class=\"error\">Warning: Plugins directory not detected in import file.</li>");
|
163 |
+
}
|
164 |
+
|
165 |
+
//if there is a database dump to restore
|
166 |
+
if(glob($restoration_dir_path . "/*.sql")) {
|
167 |
+
//collect connection information from form
|
168 |
+
fwrite($fh, "<li>Restoring database...");
|
169 |
+
$db_name = $_POST['db_name'];
|
170 |
+
$db_user = $_POST['db_user'];
|
171 |
+
$db_pass = $_POST['db_pass'];
|
172 |
+
$db_host = $_POST['db_host'];
|
173 |
+
$table_prefix = $_POST['table_prefix'];
|
174 |
+
$user_id = $_POST['user_id'];
|
175 |
+
//Connect to DB
|
176 |
+
$dbc = mysqli_connect($db_host, $db_user, $db_pass, $db_name); //OR die ('Could not connect to your database: ' . );
|
177 |
+
if ( !$dbc ) {
|
178 |
+
fwrite($fh, "</li><li class=\"error\">Unable to connect to your current database: " .mysqli_connect_error() ."</li></ul>");
|
179 |
+
recursive_delete($restoration_dir_path);
|
180 |
+
unlink(BACKUP_PATH . $restore_file_name);
|
181 |
+
fclose($fh);
|
182 |
+
die();
|
183 |
+
}
|
184 |
+
//get siteurl
|
185 |
+
$q1 = "SELECT option_value FROM " .$table_prefix ."options WHERE option_name =\"siteurl\";";
|
186 |
+
if ($result = mysqli_query($dbc, $q1)) {
|
187 |
+
while ($row = mysqli_fetch_row($result)) {
|
188 |
+
$siteurl = $row[0];
|
189 |
+
}
|
190 |
+
mysqli_free_result($result);
|
191 |
+
} else {
|
192 |
+
fwrite($fh, "</li><li class=\"error\">Unable to get current site URL from database. Please try again.</li></ul>");
|
193 |
+
recursive_delete($restoration_dir_path);
|
194 |
+
unlink(BACKUP_PATH . $restore_file_name);
|
195 |
+
fclose($fh);
|
196 |
+
die();
|
197 |
+
}
|
198 |
+
//get homeurl
|
199 |
+
$q2 = "SELECT option_value FROM " .$table_prefix ."options WHERE option_name =\"home\";";
|
200 |
+
if ($result = mysqli_query($dbc, $q2)) {
|
201 |
+
while ($row = mysqli_fetch_row($result)) {
|
202 |
+
$homeurl = $row[0];
|
203 |
+
}
|
204 |
+
mysqli_free_result($result);
|
205 |
+
} else {
|
206 |
+
fwrite($fh, "</li><li class=\"error\">Unable to get current home URL from database. Please try again.</li></ul>");
|
207 |
+
recursive_delete($restoration_dir_path);
|
208 |
+
unlink(BACKUP_PATH . $restore_file_name);
|
209 |
+
fclose($fh);
|
210 |
+
die();
|
211 |
+
}
|
212 |
+
//get user login
|
213 |
+
$q3 = "SELECT user_login FROM ". $table_prefix ."users WHERE ID=" .$user_id .";";
|
214 |
+
if ($result = mysqli_query($dbc, $q3)) {
|
215 |
+
while ($row = mysqli_fetch_row($result)) {
|
216 |
+
$user_login = $row[0];
|
217 |
+
}
|
218 |
+
mysqli_free_result($result);
|
219 |
+
} else {
|
220 |
+
fwrite($fh, "</li><li class=\"error\">Unable to get current user ID from database. Please try again.</li></ul>");
|
221 |
+
recursive_delete($restoration_dir_path);
|
222 |
+
unlink(BACKUP_PATH . $restore_file_name);
|
223 |
+
fclose($fh);
|
224 |
+
die();
|
225 |
+
}
|
226 |
+
//get user pass
|
227 |
+
$q4 = "SELECT user_pass FROM ". $table_prefix ."users WHERE ID=" .$user_id .";";
|
228 |
+
if ($result = mysqli_query($dbc, $q4)) {
|
229 |
+
while ($row = mysqli_fetch_row($result)) {
|
230 |
+
$user_pass = $row[0];
|
231 |
+
}
|
232 |
+
mysqli_free_result($result);
|
233 |
+
} else {
|
234 |
+
fwrite($fh, "</li><li class=\"error\">Unable to get current user password from database. Please try again.</li></ul>");
|
235 |
+
recursive_delete($restoration_dir_path);
|
236 |
+
unlink(BACKUP_PATH . $restore_file_name);
|
237 |
+
fclose($fh);
|
238 |
+
die();
|
239 |
+
}
|
240 |
+
//get user email
|
241 |
+
$q5 = "SELECT user_email FROM ". $table_prefix ."users WHERE ID=" .$user_id ."";
|
242 |
+
if ($result = mysqli_query($dbc, $q5)) {
|
243 |
+
while ($row = mysqli_fetch_row($result)) {
|
244 |
+
$user_email = $row[0];
|
245 |
+
}
|
246 |
+
mysqli_free_result($result);
|
247 |
+
} else {
|
248 |
+
fwrite($fh, "</li><li class=\"error\">Unable to get current user email from database. Please try again.</li></ul>");
|
249 |
+
recursive_delete($restoration_dir_path);
|
250 |
+
unlink(BACKUP_PATH . $restore_file_name);
|
251 |
+
fclose($fh);
|
252 |
+
die();
|
253 |
+
}
|
254 |
+
//Collect previous backup site url start
|
255 |
+
$import_siteinfo_lines = file($restoration_dir_path .'/backupsiteinfo.txt');
|
256 |
+
$import_siteurl = trim($import_siteinfo_lines[0]);
|
257 |
+
$current_siteurl = trim($siteurl ,'/');
|
258 |
+
$import_table_prefix = $import_siteinfo_lines[1];
|
259 |
+
//import the database
|
260 |
+
if(!db_import($restoration_dir_path, $import_siteurl, $current_siteurl, $table_prefix, $import_table_prefix, $dbc)) {
|
261 |
+
fwrite($fh, "</li><li class=\"error\">Unable to get import your database. This may require importing the file manually.</li></ul>");
|
262 |
+
recursive_delete($restoration_dir_path);
|
263 |
+
unlink(BACKUP_PATH . $restore_file_name);
|
264 |
+
fclose($fh);
|
265 |
+
die();
|
266 |
+
}
|
267 |
+
//update the database
|
268 |
+
$q6 = "UPDATE ". $table_prefix ."options SET option_value=\"" .$current_siteurl ."\" WHERE option_name=\"siteurl\"";
|
269 |
+
$q7 = "UPDATE ". $table_prefix ."options SET option_value=\"" .$homeurl ."\" WHERE option_name=\"home\"";
|
270 |
+
$q8 = "UPDATE ". $table_prefix ."users SET user_login=\"" .$user_login ."\", user_pass=\"" .$user_pass ."\", user_email=\"" .$user_email ."\" WHERE ID=\"" .$user_id ."\"";
|
271 |
+
if(!mysqli_query($dbc, $q6) ) {
|
272 |
+
fwrite($fh, "</li><li class=\"error\">Unable to update your current site URL value. This may require importing the file manually.</li></ul>");
|
273 |
+
recursive_delete($restoration_dir_path);
|
274 |
+
unlink(BACKUP_PATH . $restore_file_name);
|
275 |
+
fclose($fh);
|
276 |
+
die();
|
277 |
+
}
|
278 |
+
if(!mysqli_query($dbc, $q7) ) {
|
279 |
+
fwrite($fh, "</li><li class=\"error\">Unable to update your current home URL value. This may require importing the file manually.</li></ul>");
|
280 |
+
recursive_delete($restoration_dir_path);
|
281 |
+
unlink(BACKUP_PATH . $restore_file_name);
|
282 |
+
fclose($fh);
|
283 |
+
die();
|
284 |
+
}
|
285 |
+
if(!mysqli_query($dbc, $q8) ) {
|
286 |
+
fwrite($fh, "</li><li class=\"error\">Unable to update your user information. This may require importing the file manually.</li></ul>");
|
287 |
+
recursive_delete($restoration_dir_path);
|
288 |
+
unlink(BACKUP_PATH . $restore_file_name);
|
289 |
+
fclose($fh);
|
290 |
+
die();
|
291 |
+
}
|
292 |
+
fwrite($fh, "Done!</li>");
|
293 |
+
} else {
|
294 |
+
fwrite($fh, "<li class=\"error\">Warning: Database not detected in import file.</li>");
|
295 |
+
}
|
296 |
+
|
297 |
+
//Disconnect
|
298 |
+
mysqli_close($dbc);
|
299 |
+
|
300 |
+
//Delete the restoration directory
|
301 |
+
recursive_delete($restoration_dir_path);
|
302 |
+
|
303 |
+
//Delete zip
|
304 |
+
unlink(BACKUP_PATH . $restore_file_name);
|
305 |
+
|
306 |
+
//close log file
|
307 |
+
fwrite($fh, '<li>Restoration complete. Please refresh the page.</li>');
|
308 |
+
fwrite($fh, '</ul>');
|
309 |
+
fclose($fh);
|
310 |
+
|
311 |
+
//End backup function
|
312 |
+
die();
|
js/ajaxfileupload.js
ADDED
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
jQuery.extend({
|
3 |
+
|
4 |
+
|
5 |
+
createUploadIframe: function(id, uri)
|
6 |
+
{
|
7 |
+
//create frame
|
8 |
+
var frameId = 'jUploadFrame' + id;
|
9 |
+
var iframeHtml = '<iframe id="' + frameId + '" name="' + frameId + '" style="position:absolute; top:-9999px; left:-9999px"';
|
10 |
+
if(window.ActiveXObject)
|
11 |
+
{
|
12 |
+
if(typeof uri== 'boolean'){
|
13 |
+
iframeHtml += ' src="' + 'javascript:false' + '"';
|
14 |
+
|
15 |
+
}
|
16 |
+
else if(typeof uri== 'string'){
|
17 |
+
iframeHtml += ' src="' + uri + '"';
|
18 |
+
|
19 |
+
}
|
20 |
+
}
|
21 |
+
iframeHtml += ' />';
|
22 |
+
jQuery(iframeHtml).appendTo(document.body);
|
23 |
+
|
24 |
+
return jQuery('#' + frameId).get(0);
|
25 |
+
},
|
26 |
+
createUploadForm: function(id, fileElementId, data)
|
27 |
+
{
|
28 |
+
//create form
|
29 |
+
var formId = 'jUploadForm' + id;
|
30 |
+
var fileId = 'jUploadFile' + id;
|
31 |
+
var form = jQuery('<form action="" method="POST" name="' + formId + '" id="' + formId + '" enctype="multipart/form-data"></form>');
|
32 |
+
if(data)
|
33 |
+
{
|
34 |
+
for(var i in data)
|
35 |
+
{
|
36 |
+
jQuery('<input type="hidden" name="' + i + '" value="' + data[i] + '" />').appendTo(form);
|
37 |
+
}
|
38 |
+
}
|
39 |
+
var oldElement = jQuery('#' + fileElementId);
|
40 |
+
var newElement = jQuery(oldElement).clone();
|
41 |
+
jQuery(oldElement).attr('id', fileId);
|
42 |
+
jQuery(oldElement).before(newElement);
|
43 |
+
jQuery(oldElement).appendTo(form);
|
44 |
+
|
45 |
+
|
46 |
+
|
47 |
+
//set attributes
|
48 |
+
jQuery(form).css('position', 'absolute');
|
49 |
+
jQuery(form).css('top', '-1200px');
|
50 |
+
jQuery(form).css('left', '-1200px');
|
51 |
+
jQuery(form).appendTo('body');
|
52 |
+
return form;
|
53 |
+
},
|
54 |
+
|
55 |
+
ajaxFileUpload: function(s) {
|
56 |
+
// TODO introduce global settings, allowing the client to modify them for all requests, not only timeout
|
57 |
+
s = jQuery.extend({}, jQuery.ajaxSettings, s);
|
58 |
+
var id = new Date().getTime()
|
59 |
+
var form = jQuery.createUploadForm(id, s.fileElementId, (typeof(s.data)=='undefined'?false:s.data));
|
60 |
+
var io = jQuery.createUploadIframe(id, s.secureuri);
|
61 |
+
var frameId = 'jUploadFrame' + id;
|
62 |
+
var formId = 'jUploadForm' + id;
|
63 |
+
// Watch for a new set of requests
|
64 |
+
if ( s.global && ! jQuery.active++ )
|
65 |
+
{
|
66 |
+
jQuery.event.trigger( "ajaxStart" );
|
67 |
+
}
|
68 |
+
var requestDone = false;
|
69 |
+
// Create the request object
|
70 |
+
var xml = {}
|
71 |
+
if ( s.global )
|
72 |
+
jQuery.event.trigger("ajaxSend", [xml, s]);
|
73 |
+
// Wait for a response to come back
|
74 |
+
var uploadCallback = function(isTimeout)
|
75 |
+
{
|
76 |
+
var io = document.getElementById(frameId);
|
77 |
+
try
|
78 |
+
{
|
79 |
+
if(io.contentWindow)
|
80 |
+
{
|
81 |
+
xml.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
|
82 |
+
xml.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
|
83 |
+
|
84 |
+
}else if(io.contentDocument)
|
85 |
+
{
|
86 |
+
xml.responseText = io.contentDocument.document.body?io.contentDocument.document.body.innerHTML:null;
|
87 |
+
xml.responseXML = io.contentDocument.document.XMLDocument?io.contentDocument.document.XMLDocument:io.contentDocument.document;
|
88 |
+
}
|
89 |
+
}catch(e)
|
90 |
+
{
|
91 |
+
jQuery.handleError(s, xml, null, e);
|
92 |
+
}
|
93 |
+
if ( xml || isTimeout == "timeout")
|
94 |
+
{
|
95 |
+
requestDone = true;
|
96 |
+
var status;
|
97 |
+
try {
|
98 |
+
status = isTimeout != "timeout" ? "success" : "error";
|
99 |
+
// Make sure that the request was successful or notmodified
|
100 |
+
if ( status != "error" )
|
101 |
+
{
|
102 |
+
// process the data (runs the xml through httpData regardless of callback)
|
103 |
+
var data = jQuery.uploadHttpData( xml, s.dataType );
|
104 |
+
// If a local callback was specified, fire it and pass it the data
|
105 |
+
if ( s.success )
|
106 |
+
s.success( data, status );
|
107 |
+
|
108 |
+
// Fire the global callback
|
109 |
+
if( s.global )
|
110 |
+
jQuery.event.trigger( "ajaxSuccess", [xml, s] );
|
111 |
+
} else
|
112 |
+
jQuery.handleError(s, xml, status);
|
113 |
+
} catch(e)
|
114 |
+
{
|
115 |
+
status = "error";
|
116 |
+
jQuery.handleError(s, xml, status, e);
|
117 |
+
}
|
118 |
+
|
119 |
+
// The request was completed
|
120 |
+
if( s.global )
|
121 |
+
jQuery.event.trigger( "ajaxComplete", [xml, s] );
|
122 |
+
|
123 |
+
// Handle the global AJAX counter
|
124 |
+
if ( s.global && ! --jQuery.active )
|
125 |
+
jQuery.event.trigger( "ajaxStop" );
|
126 |
+
|
127 |
+
// Process result
|
128 |
+
if ( s.complete )
|
129 |
+
s.complete(xml, status);
|
130 |
+
|
131 |
+
jQuery(io).unbind()
|
132 |
+
|
133 |
+
setTimeout(function()
|
134 |
+
{ try
|
135 |
+
{
|
136 |
+
jQuery(io).remove();
|
137 |
+
jQuery(form).remove();
|
138 |
+
|
139 |
+
} catch(e)
|
140 |
+
{
|
141 |
+
jQuery.handleError(s, xml, null, e);
|
142 |
+
}
|
143 |
+
|
144 |
+
}, 100)
|
145 |
+
|
146 |
+
xml = null
|
147 |
+
|
148 |
+
}
|
149 |
+
}
|
150 |
+
// Timeout checker
|
151 |
+
if ( s.timeout > 0 )
|
152 |
+
{
|
153 |
+
setTimeout(function(){
|
154 |
+
// Check to see if the request is still happening
|
155 |
+
if( !requestDone ) uploadCallback( "timeout" );
|
156 |
+
}, s.timeout);
|
157 |
+
}
|
158 |
+
try
|
159 |
+
{
|
160 |
+
|
161 |
+
var form = jQuery('#' + formId);
|
162 |
+
jQuery(form).attr('action', s.url);
|
163 |
+
jQuery(form).attr('method', 'POST');
|
164 |
+
jQuery(form).attr('target', frameId);
|
165 |
+
if(form.encoding)
|
166 |
+
{
|
167 |
+
jQuery(form).attr('encoding', 'multipart/form-data');
|
168 |
+
}
|
169 |
+
else
|
170 |
+
{
|
171 |
+
jQuery(form).attr('enctype', 'multipart/form-data');
|
172 |
+
}
|
173 |
+
jQuery(form).submit();
|
174 |
+
|
175 |
+
} catch(e)
|
176 |
+
{
|
177 |
+
jQuery.handleError(s, xml, null, e);
|
178 |
+
}
|
179 |
+
|
180 |
+
jQuery('#' + frameId).load(uploadCallback );
|
181 |
+
return {abort: function () {}};
|
182 |
+
|
183 |
+
},
|
184 |
+
|
185 |
+
uploadHttpData: function( r, type ) {
|
186 |
+
var data = !type;
|
187 |
+
data = type == "xml" || data ? r.responseXML : r.responseText;
|
188 |
+
// If the type is "script", eval it in global context
|
189 |
+
if ( type == "script" )
|
190 |
+
jQuery.globalEval( data );
|
191 |
+
// Get the JavaScript object, if JSON is used.
|
192 |
+
if ( type == "json" )
|
193 |
+
eval( "data = " + data );
|
194 |
+
// evaluate scripts within html
|
195 |
+
if ( type == "html" )
|
196 |
+
jQuery("<div>").html(data).evalScripts();
|
197 |
+
|
198 |
+
return data;
|
199 |
+
}
|
200 |
+
})
|
201 |
+
|
js/wp-backitup.js
CHANGED
@@ -1,4 +1,5 @@
|
|
1 |
jQuery(document).ready(function($) {
|
|
|
2 |
//define backup variables
|
3 |
var wpBackitupBackup = {
|
4 |
action: 'wpbackitup_backup',
|
@@ -45,4 +46,24 @@ jQuery(document).ready(function($) {
|
|
45 |
$("#wp-backitup-php").html(response); //Return PHP messages, used for development
|
46 |
});
|
47 |
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
});
|
1 |
jQuery(document).ready(function($) {
|
2 |
+
|
3 |
//define backup variables
|
4 |
var wpBackitupBackup = {
|
5 |
action: 'wpbackitup_backup',
|
46 |
$("#wp-backitup-php").html(response); //Return PHP messages, used for development
|
47 |
});
|
48 |
})
|
49 |
+
|
50 |
+
//execture restore on button click
|
51 |
+
$("#restore-form").submit(function() {
|
52 |
+
$('#wp-backitup-restore .status-icon').css('visibility','visible'); //display process icon
|
53 |
+
$("#wp-backitup-status").empty(); //clear status messages
|
54 |
+
setInterval(logreader, 1000); //check for status updates every second
|
55 |
+
$("#restore-form").attr("target","upload_target"); //specify target for form submission
|
56 |
+
$("#upload_target").load(function (){
|
57 |
+
importRestore(); //on iframe load, run restore function
|
58 |
+
});
|
59 |
+
});
|
60 |
+
|
61 |
+
//define importRestore function
|
62 |
+
function importRestore() {
|
63 |
+
var ret = frames['upload_target'].document.getElementsByTagName("body")[0].innerHTML; //process upload
|
64 |
+
$("#wp-backitup-php").html(ret); //Return PHP messages, used for development
|
65 |
+
download(); //Create download link
|
66 |
+
clearInterval(logreader); //Stop checking for status messages
|
67 |
+
$('#wp-backitup-restore .status-icon').fadeOut(1000); //hide process icon
|
68 |
+
}
|
69 |
});
|
readme.txt
CHANGED
@@ -1,69 +1,70 @@
|
|
1 |
=== Plugin Name ===
|
2 |
Contributors: jcpeden
|
3 |
-
Donate link: http://www.
|
4 |
Tags: backup, restore, clone, database, wp-content, files
|
5 |
Requires at least: 3.4
|
6 |
-
Tested up to: 3.
|
7 |
-
Stable tag: 1.0.
|
8 |
License: GPLv2 or later
|
9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
10 |
|
11 |
-
WP
|
12 |
|
13 |
== Description ==
|
14 |
|
15 |
-
WP
|
16 |
-
backup of any site and, using WP
|
17 |
|
18 |
== Installation ==
|
19 |
|
20 |
Installation of the plugin is straightforward:
|
21 |
|
22 |
-
1. Upload the directory `wp-
|
23 |
1. Activate the plugin through the `Plugins` menu in WordPress.
|
24 |
-
1. Through the Wordpress dashboard, browse to Tools > WP
|
25 |
|
26 |
== Frequently Asked Questions ==
|
27 |
-
|
|
|
28 |
= Will the plugin work on shared hosting/sub domains/webhost xxx? =
|
29 |
Yes
|
30 |
-
|
31 |
= Will WP Backitup work on Windows hosting? =
|
32 |
Yes
|
33 |
-
|
34 |
= Are you going to be making progress bars both for backing up and restoring with this plugin? =
|
35 |
Not at this time.
|
36 |
-
|
37 |
= Can this plugin back to Amazon S3? =
|
38 |
Not at this time.
|
39 |
-
|
40 |
= Is there an auto back up schedule feature? =
|
41 |
Not at this time.
|
42 |
-
|
43 |
= Will the plugin work with Wordpres version x.x? =
|
44 |
The plugin works on the latest release of WordPress and is updated to function with all new releases.
|
45 |
-
|
46 |
= Can this backup one version of WordPress to a different version? =
|
47 |
No. It is absolutely critical that your WordPress versions are exactly the same.
|
48 |
-
|
49 |
= Will WP Backitup work on WordPress Multisite? =
|
50 |
It is untested with Wordpress multisite and probably will not work.
|
51 |
-
|
52 |
= Does the plugin copy the database details as well? =
|
53 |
Yes, a database dump is created with each backup.
|
54 |
-
|
55 |
= Can I make a basic WordPress site, with all my desired plugins and settings, make a few pages, setup permalinks, remove all the default junk and load in a basic themplate? =
|
56 |
Yes. WP Backitup can be used to create a good starting point for any and all sites you work on.
|
57 |
-
|
58 |
= Does WP Backitup need to be installed? =
|
59 |
Yes. You must install the WP Backitup plugin on the site you wish to backup and the site you wish to restore to. Its just a simple plugin.
|
60 |
-
|
61 |
= Does WP Backitup backup plugins settings or just the plugins themselves? =
|
62 |
WP Backitup creates a database dump and a backup of all your themes, plugins and uploads.
|
63 |
-
|
64 |
= Do you have any ideas about how large a blog is too big for WP Backitup to handle? =
|
65 |
I`ve tested up to 5 themes, 20 plugins and 100 posts/pages without any issues.
|
66 |
-
|
67 |
= Do you do regularly update this product to match with WP version updates? =
|
68 |
Yes.
|
69 |
|
1 |
=== Plugin Name ===
|
2 |
Contributors: jcpeden
|
3 |
+
Donate link: http://www.wpbackitup.com
|
4 |
Tags: backup, restore, clone, database, wp-content, files
|
5 |
Requires at least: 3.4
|
6 |
+
Tested up to: 3.4.2
|
7 |
+
Stable tag: 1.0.7
|
8 |
License: GPLv2 or later
|
9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
10 |
|
11 |
+
WP BackItUp allows you to backup your database and wp-content folder. This allows you to quickly clone, backup and restore any of your Wordpress sites.
|
12 |
|
13 |
== Description ==
|
14 |
|
15 |
+
WP BackItUp uses nothing but PHP to allow you to backup and restore your Wordpress database, plugins, themes and uploads directories. You can create a
|
16 |
+
backup of any site and, using WP BackItUp, quickly import your files, settings and content into a new site.
|
17 |
|
18 |
== Installation ==
|
19 |
|
20 |
Installation of the plugin is straightforward:
|
21 |
|
22 |
+
1. Upload the directory `wp-backitup` to the `/wp-content/plugins/` directory.
|
23 |
1. Activate the plugin through the `Plugins` menu in WordPress.
|
24 |
+
1. Through the Wordpress dashboard, browse to Tools > WP BackItUp.
|
25 |
|
26 |
== Frequently Asked Questions ==
|
27 |
+
|
28 |
+
|
29 |
= Will the plugin work on shared hosting/sub domains/webhost xxx? =
|
30 |
Yes
|
31 |
+
|
32 |
= Will WP Backitup work on Windows hosting? =
|
33 |
Yes
|
34 |
+
|
35 |
= Are you going to be making progress bars both for backing up and restoring with this plugin? =
|
36 |
Not at this time.
|
37 |
+
|
38 |
= Can this plugin back to Amazon S3? =
|
39 |
Not at this time.
|
40 |
+
|
41 |
= Is there an auto back up schedule feature? =
|
42 |
Not at this time.
|
43 |
+
|
44 |
= Will the plugin work with Wordpres version x.x? =
|
45 |
The plugin works on the latest release of WordPress and is updated to function with all new releases.
|
46 |
+
|
47 |
= Can this backup one version of WordPress to a different version? =
|
48 |
No. It is absolutely critical that your WordPress versions are exactly the same.
|
49 |
+
|
50 |
= Will WP Backitup work on WordPress Multisite? =
|
51 |
It is untested with Wordpress multisite and probably will not work.
|
52 |
+
|
53 |
= Does the plugin copy the database details as well? =
|
54 |
Yes, a database dump is created with each backup.
|
55 |
+
|
56 |
= Can I make a basic WordPress site, with all my desired plugins and settings, make a few pages, setup permalinks, remove all the default junk and load in a basic themplate? =
|
57 |
Yes. WP Backitup can be used to create a good starting point for any and all sites you work on.
|
58 |
+
|
59 |
= Does WP Backitup need to be installed? =
|
60 |
Yes. You must install the WP Backitup plugin on the site you wish to backup and the site you wish to restore to. Its just a simple plugin.
|
61 |
+
|
62 |
= Does WP Backitup backup plugins settings or just the plugins themselves? =
|
63 |
WP Backitup creates a database dump and a backup of all your themes, plugins and uploads.
|
64 |
+
|
65 |
= Do you have any ideas about how large a blog is too big for WP Backitup to handle? =
|
66 |
I`ve tested up to 5 themes, 20 plugins and 100 posts/pages without any issues.
|
67 |
+
|
68 |
= Do you do regularly update this product to match with WP version updates? =
|
69 |
Yes.
|
70 |
|
screenshots/screenshot-1.png
ADDED
Binary file
|
screenshots/screenshot-2.png
ADDED
Binary file
|
screenshots/screenshot-3.png
ADDED
Binary file
|
wp-backitup.php
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
<?php
|
2 |
/**
|
3 |
-
* Plugin Name: WP
|
4 |
* Plugin URI: http://www.wpbackitup.com
|
5 |
* Description: Backup your content, settings, themes, plugins and media in just a few simple clicks.
|
6 |
-
* Version: 1.0.
|
7 |
* Author: John Peden
|
8 |
* Author URI: http://www.johncpeden.com
|
9 |
* License: GPLv2 or later
|
1 |
<?php
|
2 |
/**
|
3 |
+
* Plugin Name: WP BackItUp
|
4 |
* Plugin URI: http://www.wpbackitup.com
|
5 |
* Description: Backup your content, settings, themes, plugins and media in just a few simple clicks.
|
6 |
+
* Version: 1.0.7
|
7 |
* Author: John Peden
|
8 |
* Author URI: http://www.johncpeden.com
|
9 |
* License: GPLv2 or later
|