diff --git a/.gitignore b/.gitignore index 4f33c66..9e8086e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ node_modules/ dist/ vendor/ -src/php/api/config.php \ No newline at end of file +src/php/api/config.php +src/php/api/migrate.php \ No newline at end of file diff --git a/README.md b/README.md index 7e2c9dc..c19d1ae 100644 --- a/README.md +++ b/README.md @@ -25,3 +25,11 @@ It's less useful, but `npm run serve-frontend-only` will bundle and serve _only_ ## Production `npm run bundle` bundles and minifies the frontend stuff and also copies the backend stuff to `dist`. Be sure to run `npm run clear` to delete the contents of `dist` and `.cache` before using `npm run bundle` to make sure you don't get old dev versions of the bundled code included in your upload. + +## Migration + +There is a script called `src/php/api/migrate.php.changeme` that can be used to help with the migration process from a `version1` Lexiconga database into a `master` database. **Note:** Migration is intended only for migrating from an old server to a freshly-installed/empty new database. To use this, copy `src/php/api/migrate.php.changeme` to `migrate.php` somewhere in the `version1` project (probably in `/php`) and copy the same to `/api/migrate.php` in your `master` project, making sure that all the variables for referencing the databases are correct. + +Visit `migrate.php` on your `version1` server with `?outgoing=true` set in order to begin the transfer. The other server's `migrate.php` will receive an "incoming" request multiple times, and your screen will display messages as it works. + +_DELETE THESE `migrate.php` FILES IMMEDIATELY AFTER MIGRATION IS COMPLETE!_. diff --git a/src/php/api/migrate.php.changeme b/src/php/api/migrate.php.changeme new file mode 100644 index 0000000..e0d7313 --- /dev/null +++ b/src/php/api/migrate.php.changeme @@ -0,0 +1,274 @@ +' . PHP_EOL; + echo 'Starting migration from ' . VERSION1_DATABASE_SERVERNAME . ' db ' . VERSION1_DATABASE_NAME . PHP_EOL . 'To ' . MIGRATE_TO . PHP_EOL . PHP_EOL; + + $dbconnection = new PDO('mysql:host=' . VERSION1_DATABASE_SERVERNAME . ';dbname=' . VERSION1_DATABASE_NAME . ';charset=utf8', VERSION1_DATABASE_USERNAME, VERSION1_DATABASE_PASSWORD); + $dbconnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + // $dbconnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); + $dbconnection->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); + try { + $users_stmt = $dbconnection->prepare('SELECT * FROM `users`'); + $users_stmt->execute(); + if ($users_stmt) { + $users = $users_stmt->fetchAll(); + if ($users !== false) { + echo count($users) . ' Users' . PHP_EOL; + + foreach($users as $user) { + $send_user_response = send('user', $user); + + if ($send_user_response === "GOT USER") { + echo PHP_EOL . 'User ' . $user['id'] . ' sent successfully' . PHP_EOL; + + $dictionaries_stmt = $dbconnection->prepare('SELECT * FROM `dictionaries` WHERE `user`=?'); + $dictionaries_stmt->execute(array(intval($user['id']))); + if ($dictionaries_stmt) { + $dictionaries = $dictionaries_stmt->fetchAll(); + if ($dictionaries !== false) { + echo 'User ' . $user['id'] . ' has ' . count($dictionaries) . ' Dictionaries' . PHP_EOL; + + $send_dictionaries_response = send('dictionaries', $dictionaries, array('user' => $user['id'])); + + if ($send_dictionaries_response === 'GOT DICTIONARIES') { + echo 'Dictionaries sent successfully' . PHP_EOL; + + foreach($dictionaries as $dictionary) { + $words_stmt = $dbconnection->prepare('SELECT * FROM `words` WHERE `dictionary`=?'); + $words_stmt->execute(array(intval($dictionary['id']))); + if ($words_stmt) { + $words = $words_stmt->fetchAll(); + if ($words !== false) { + $send_words_response = send('words', $words); + + if ($send_words_response === 'GOT WORDS') { + echo 'Words for Dictionary ' . $dictionary['id'] . ' sent successfully' . PHP_EOL; + } else { + echo var_export($send_words_response, true) . PHP_EOL . PHP_EOL; + } + } else { + echo '$words_stmt->fetchAll() failed.' . PHP_EOL . var_export($words_stmt->errorInfo(), true) . PHP_EOL . PHP_EOL; + } + } else { + echo '$words_stmt failed' . PHP_EOL . PHP_EOL; + } + } + } else { + echo var_export($send_dictionaries_response, true) . PHP_EOL . PHP_EOL; + } + } else { + echo '$dictionaries_stmt->fetchAll() failed.' . PHP_EOL . var_export($dictionaries_stmt->errorInfo(), true) . PHP_EOL . PHP_EOL; + } + } else { + echo '$dictionaries_stmt failed' . PHP_EOL . PHP_EOL; + } + } else { + var_dump($send_user_response) . PHP_EOL . PHP_EOL; + } + } + } else { + echo '$users_stmt->fetchAll() failed.' . PHP_EOL . var_export($users_stmt->errorInfo(), true) . PHP_EOL . PHP_EOL; + } + } else { + echo '$users_stmt failed' . PHP_EOL . PHP_EOL; + } + } + catch (PDOException $ex) { + echo var_export($ex, true) . PHP_EOL . PHP_EOL; + } + + echo ''; +} else if ($incoming !== false) { + $type = isset($_POST['type']) ? $_POST['type'] : false; + + if ($type !== false) { + $dbconnection = new PDO('mysql:host=' . NEW_DATABASE_SERVERNAME . ';dbname=' . NEW_DATABASE_NAME . ';charset=utf8', NEW_DATABASE_USERNAME, NEW_DATABASE_PASSWORD); + $dbconnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + switch($type) { + case 'user': { + if ($incoming === null) { + echo 'Invalid JSON'; + } else { + $user_stmt = $dbconnection->prepare('INSERT INTO `users`(`id`, `email`, `old_password`, `password`, `public_name`, `current_dictionary`, `allow_email`, `last_login`, `password_reset_code`, `password_reset_date`, `created_on`) VALUES (?,?,?,?,?,?,?,?,?,?,?)'); + $user_stmt->execute(array( + intval($incoming['id']), + $incoming['email'], + $incoming['password'], + null, + $incoming['public_name'], + intval($incoming['current_dictionary']), + intval($incoming['allow_email']), + $incoming['last_login'], + null, + null, + $incoming['created_on'], + )); + if ($user_stmt) { + echo 'GOT USER'; + } else { + var_dump($user_stmt->errorInfo()); + } + } + break; + } + case 'dictionaries': { + if ($incoming === null) { + echo 'Invalid JSON'; + } else { + if (count($incoming) === 0) { + echo 'Need new dictionary for user ' . $_POST['user'] . ': '; + + $new_id = mt_rand(1000, 999999999); + + $user = intval($_POST['user']); + $insert_dictionary_query = "INSERT INTO dictionaries (id, user, description, created_on) VALUES (?, ?, ?, ?)"; + $insert_dictionary_stmt = $dbconnection->prepare($insert_dictionary_query); + $insert_dictionary = $insert_dictionary_stmt->execute(array($new_id, $user, 'A new dictionary.', time())); + + if ($insert_dictionary) { + $insert_linguistics_query = "INSERT INTO dictionary_linguistics (dictionary, parts_of_speech, exceptions, orthography_notes, grammar_notes) VALUES ($new_id, ?, ?, ?, ?)"; + $insert_linguistics_stmt = $dbconnection->prepare($insert_linguistics_query); + $insert_linguistics = $insert_linguistics_stmt->execute(array('Noun,Adjective,Verb', '', '', '')); + + if ($insert_linguistics === true) { + $update_query = 'UPDATE users SET current_dictionary=? WHERE id=?'; + $update_stmt = $dbconnection->prepare($update_query); + $update = $update_stmt->execute(array($new_id, $user)); + if ($update) { + echo 'CREATED DICTIONARY'; + } else { + var_dump($update_stmt); + } + } else { + var_dump($insert_linguistics_stmt->errorInfo()); + } + } else { + var_dump($insert_dictionary_stmt->errorInfo()); + } + } else { + $dictionaries_query = 'INSERT INTO `dictionaries`(`id`, `user`, `name`, `specification`, `description`, `allow_duplicates`, `case_sensitive`, `sort_by_definition`, `theme`, `is_public`, `last_updated`, `created_on`) VALUES '; + $linguistics_query = "INSERT INTO dictionary_linguistics (dictionary, parts_of_speech, exceptions, orthography_notes, grammar_notes) VALUES "; + $dictionaries_params = array(); + $linguistics_params = array(); + foreach($incoming as $dictionary) { + $dictionaries_query .= '(?,?,?,?,?,?,?,?,?,?,?,?), '; + // `id`, `user`, `name`, `description`, `words`, `next_word_id`, `allow_duplicates`, `case_sensitive`, `parts_of_speech`, `sort_by_equivalent`, `is_complete`, `is_public`, `last_updated`, `created_on` + $dictionaries_params[] = intval($dictionary['id']); + $dictionaries_params[] = intval($dictionary['user']); + $dictionaries_params[] = $dictionary['name']; + $dictionaries_params[] = 'Dictionary'; + $dictionaries_params[] = fixStupidOldNonsense($dictionary['description']); + $dictionaries_params[] = intval($dictionary['allow_duplicates']); + $dictionaries_params[] = intval($dictionary['case_sensitive']); + $dictionaries_params[] = intval($dictionary['sort_by_equivalent']); + $dictionaries_params[] = 'default'; + $dictionaries_params[] = intval($dictionary['is_public']); + $dictionaries_params[] = $dictionary['last_updated'] ? strtotime($dictionary['last_updated']) : null; + $dictionaries_params[] = strtotime($dictionary['created_on']); + + $linguistics_query .= '(?, ?, ?, ?, ?), '; + $linguistics_params[] = intval($dictionary['id']); + $linguistics_params[] = $dictionary['parts_of_speech']; + $linguistics_params[] = ''; + $linguistics_params[] = ''; + $linguistics_params[] = ''; + } + $dictionaries_stmt = $dbconnection->prepare(trim($dictionaries_query, ', ')); + $dictionaries_stmt->execute($dictionaries_params); + if ($dictionaries_stmt) { + $linguistics_stmt = $dbconnection->prepare(trim($linguistics_query, ', ')); + $linguistics_stmt->execute($linguistics_params); + if ($linguistics_stmt) { + echo 'GOT DICTIONARIES'; + } else { + var_dump($linguistics_stmt->errorInfo()); + } + } else { + var_dump($dictionaries_stmt->errorInfo()); + } + } + } + break; + } + case 'words': { + if ($incoming === null) { + echo 'Invalid JSON'; + } else { + if (count($incoming) > 0) { + $words_query = 'INSERT INTO `words`(`dictionary`, `word_id`, `name`, `pronunciation`, `part_of_speech`, `definition`, `details`, `last_updated`, `created_on`) VALUES '; + $words_params = array(); + foreach($incoming as $word) { + $words_query .= '(?,?,?,?,?,?,?,?,?), '; + // `dictionary`, `word_id`, `name`, `pronunciation`, `part_of_speech`, `simple_definition`, `long_definition`, `last_updated`, `created_on` + $words_params[] = intval($word['dictionary']); + $words_params[] = intval($word['word_id']); + $words_params[] = $word['name']; + $words_params[] = $word['pronunciation']; + $words_params[] = $word['part_of_speech']; + $words_params[] = $word['simple_definition']; + $words_params[] = fixStupidOldNonsense($word['long_definition']); + $words_params[] = $word['last_updated'] ? strtotime($word['last_updated']) : null; + $words_params[] = strtotime($word['created_on']); + } + $words_stmt = $dbconnection->prepare(trim($words_query, ', ')); + $words_stmt->execute($words_params); + if ($words_stmt) { + echo 'GOT WORDS'; + } else { + var_dump($words_stmt->errorInfo()); + } + } else { + echo 'NO WORDS'; + } + } + break; + } + } + } +} else { + echo 'no' . PHP_EOL . PHP_EOL; +} + +function send($type, $data, $additional_data = array()) { + $send_data = array_merge(array('type' => $type, 'incoming' => json_encode($data)), $additional_data); + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, MIGRATE_TO . '/api/migrate.php'); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($send_data)); + + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + $server_output = curl_exec($ch); + + curl_close ($ch); + + return $server_output; +} + +function fixStupidOldNonsense($markdown) { + $markdown = str_replace('"', '"', $markdown); + $markdown = str_replace(''', "'", $markdown); + $markdown = str_replace('\', '\\', $markdown); + $markdown = str_replace('
', '\\n', $markdown); + return $markdown; +}