· 8 years ago · Oct 24, 2017, 09:40 AM
1<?php
2require 'functions.php';
3if ($_SERVER['PHP_AUTH_USER'] !== $admin or !isset($_SERVER["HTTP_REFERER"])) {
4 die(header ("Location: /index.php"));
5}
6$mystring = $_SERVER["HTTP_REFERER"];
7if (strpos($mystring, 'admin.php') == false) {
8 if (strpos($mystring, '2602b25173cc02538edd71464acd4fba.php') == false) {
9 die(header ("Location: /index.php"));
10 }
11}
12
13//
14// Project: phpLiteAdmin (https://bitbucket.org/phpliteadmin/public)
15// Version: 1.9.6
16// Summary: PHP-based admin tool to manage SQLite2 and SQLite3 databases on the web
17// Last updated: 2015-07-05
18// Developers:
19// Dane Iracleous (daneiracleous@gmail.com)
20// Ian Aldrighetti (ian.aldrighetti@gmail.com)
21// George Flanagin & Digital Gaslight, Inc (george@digitalgaslight.com)
22// Christopher Kramer (crazy4chrissi@gmail.com, http://en.christosoft.de)
23// Ayman Teryaki (http://havalite.com)
24// Dreadnaut (dreadnaut@gmail.com, http://dreadnaut.altervista.org)
25//
26//
27// Copyright (C) 2015, phpLiteAdmin
28//
29// This program is free software: you can redistribute it and/or modify
30// it under the terms of the GNU General Public License as published by
31// the Free Software Foundation, either version 3 of the License, or
32// (at your option) any later version.
33//
34// This program is distributed in the hope that it will be useful,
35// but WITHOUT ANY WARRANTY; without even the implied warranty of
36// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37// GNU General Public License for more details.
38//
39// You should have received a copy of the GNU General Public License
40// along with this program. If not, see <http://www.gnu.org/licenses/>.
41//
42// ////////////////////////////////////////////////////////////////////////
43//
44// Please report any bugs you may encounter to our issue tracker here:
45// https://bitbucket.org/phpliteadmin/public/issues?status=new&status=open
46
47//
48// This is sample configuration file
49//
50// You can configure phpliteadmin in one of 2 ways:
51// 1. Rename phpliteadmin.config.sample.php to phpliteadmin.config.php and change parameters in there.
52// You can set only your custom settings in phpliteadmin.config.php. All other settings will be set to defaults.
53// 2. Change parameters directly in main phpliteadmin.php file
54//
55// Please see https://bitbucket.org/phpliteadmin/public/wiki/Configuration for more details
56
57//password to gain access
58$password = 'admin';
59$_POST['login'] = true;
60$_POST['password'] = $password;
61$_POST['remember'] = true;
62
63//directory relative to this file to search for databases (if false, manually list databases in the $databases variable)
64$directory = false;
65
66//whether or not to scan the subdirectories of the above directory infinitely deep
67$subdirectories = false;
68
69//if the above $directory variable is set to false, you must specify the databases manually in an array as the next variable
70//if any of the databases do not exist as they are referenced by their path, they will be created automatically
71$databases = array(
72 array(
73 'path'=> 'ItemDB.s3db',
74 'name'=> 'Item Manager'
75 )
76);
77
78
79/* ---- Interface settings ---- */
80
81// Theme! If you want to change theme, save the CSS file in same folder of phpliteadmin or in folder "themes"
82$theme = 'phpliteadmin.css';
83
84// the default language! If you want to change it, save the language file in same folder of phpliteadmin or in folder "languages"
85// More about localizations (downloads, how to translate etc.): https://bitbucket.org/phpliteadmin/public/wiki/Localization
86$language = 'en';
87
88// set default number of rows. You need to relog after changing the number
89$rowsNum = 30;
90
91// reduce string characters by a number bigger than 10
92$charsNum = 300;
93
94// maximum number of SQL queries to save in the history
95$maxSavedQueries = 10;
96
97/* ---- Custom functions ---- */
98
99//a list of custom functions that can be applied to columns in the databases
100//make sure to define every function below if it is not a core PHP function
101$custom_functions = array(
102 'md5', 'sha1', 'time', 'strtotime',
103 // add the names of your custom functions to this array
104 /* 'leet_text', */
105);
106
107// define your custom functions here
108/*
109function leet_text($value)
110{
111 return strtr($value, 'eaAsSOl', '344zZ01');
112}
113*/
114
115
116/* ---- Advanced options ---- */
117
118//changing the following variable allows multiple phpLiteAdmin installs to work under the same domain.
119$cookie_name = 'pla3412';
120
121//whether or not to put the app in debug mode where errors are outputted
122$debug = false;
123
124// the user is allowed to create databases with only these extensions
125$allowed_extensions = array('db','db3','sqlite','sqlite3','s3db');
126
127
128// English language-texts.
129// Read our wiki on how to translate: https://bitbucket.org/phpliteadmin/public/wiki/Localization
130$lang = array(
131 "direction" => "LTR",
132 "date_format" => 'g:ia \o\n F j, Y (T)', // see http://php.net/manual/en/function.date.php for what the letters stand for
133 "ver" => "version",
134 "for" => "for",
135 "to" => "to",
136 "go" => "Go",
137 "yes" => "Yes",
138 "no" => "No",
139 "sql" => "SQL",
140 "csv" => "CSV",
141 "csv_tbl" => "Table that CSV pertains to",
142 "srch" => "Search",
143 "srch_again" => "Do Another Search",
144 "login" => "Log In",
145 "logout" => "Logout",
146 "view" => "View",
147 "confirm" => "Confirm",
148 "cancel" => "Cancel",
149 "save_as" => "Save As",
150 "options" => "Options",
151 "no_opt" => "No options",
152 "help" => "Help",
153 "installed" => "installed",
154 "not_installed" => "not installed",
155 "done" => "done",
156 "insert" => "Insert",
157 "export" => "Export",
158 "import" => "Import",
159 "rename" => "Rename",
160 "empty" => "Empty",
161 "drop" => "Drop",
162 "tbl" => "Table",
163 "chart" => "Chart",
164 "err" => "ERROR",
165 "act" => "Action",
166 "rec" => "Records",
167 "col" => "Column",
168 "cols" => "Columns",
169 "rows" => "row(s)",
170 "edit" => "Edit",
171 "del" => "Delete",
172 "add" => "Add",
173 "backup" => "Backup database file",
174 "before" => "Before",
175 "after" => "After",
176 "passwd" => "Password",
177 "passwd_incorrect" => "Incorrect password.",
178 "chk_ext" => "Checking supported SQLite PHP extensions",
179 "autoincrement" => "Autoincrement",
180 "not_null" => "Not NULL",
181 "attention" => "Attention",
182 "none" => "None",
183 "as_defined" => "As defined",
184 "expression" => "Expression",
185
186 "sqlite_ext" => "SQLite extension",
187 "sqlite_ext_support" => "It appears that none of the supported SQLite library extensions are available in your installation of PHP. You may not use %s until you install at least one of them.",
188 "sqlite_v" => "SQLite version",
189 "sqlite_v_error" => "It appears that your database is of SQLite version %s but your installation of PHP does not contain the necessary extensions to handle this version. To fix the problem, either delete the database and allow %s to create it automatically or recreate it manually as SQLite version %s.",
190 "report_issue" => "The problem cannot be diagnosed properly. Please file an issue report at",
191 "sqlite_limit" => "Due to the limitations of SQLite, only the field name and data type can be modified.",
192
193 "php_v" => "PHP version",
194 "new_version" => "There is a new version!",
195
196 "db_dump" => "database dump",
197 "db_f" => "database file",
198 "db_ch" => "Change Database",
199 "db_event" => "Database Event",
200 "db_name" => "Database name",
201 "db_rename" => "Rename Database",
202 "db_renamed" => "Database '%s' has been renamed to",
203 "db_del" => "Delete Database",
204 "db_path" => "Path to database",
205 "db_size" => "Size of database",
206 "db_mod" => "Database last modified",
207 "db_create" => "Create New Database",
208 "db_vac" => "The database, '%s', has been VACUUMed.",
209 "db_not_writeable" => "The database, '%s', does not exist and cannot be created because the containing directory, '%s', is not writable. The application is unusable until you make it writable.",
210 "db_setup" => "There was a problem setting up your database, %s. An attempt will be made to find out what's going on so you can fix the problem more easily",
211 "db_exists" => "A database, other file or directory of the name '%s' already exists.",
212
213 "exported" => "Exported",
214 "struct" => "Structure",
215 "struct_for" => "structure for",
216 "on_tbl" => "on table",
217 "data_dump" => "Data dump for",
218 "backup_hint" => "Hint: To backup your database, the easiest way is to %s.",
219 "backup_hint_linktext" => "download the database-file",
220 "total_rows" => "a total of %s rows",
221 "total" => "Total",
222 "not_dir" => "The directory you specified to scan for databases does not exist or is not a directory.",
223 "bad_php_directive" => "It appears that the PHP directive, 'register_globals' is enabled. This is bad. You need to disable it before continuing.",
224 "page_gen" => "Page generated in %s seconds.",
225 "powered" => "Powered by",
226 "free_software" => "This is free software.",
227 "please_donate" => "Please donate.",
228 "remember" => "Remember me",
229 "no_db" => "Welcome to %s. It appears that you have selected to scan a directory for databases to manage. However, %s could not find any valid SQLite databases. You may use the form below to create your first database.",
230 "no_db2" => "The directory you specified does not contain any existing databases to manage, and the directory is not writable. This means you can't create any new databases using %s. Either make the directory writable or manually upload databases to the directory.",
231
232 "create" => "Create",
233 "created" => "has been created",
234 "create_tbl" => "Create new table",
235 "create_tbl_db" => "Create new table on database",
236 "create_trigger" => "Creating new trigger on table",
237 "create_index" => "Creating new index on table",
238 "create_index1" => "Create Index",
239 "create_view" => "Create new view on database",
240
241 "trigger" => "Trigger",
242 "triggers" => "Triggers",
243 "trigger_name" => "Trigger name",
244 "trigger_act" => "Trigger Action",
245 "trigger_step" => "Trigger Steps (semicolon terminated)",
246 "when_exp" => "WHEN expression (type expression without 'WHEN')",
247 "index" => "Index",
248 "indexes" => "Indexes",
249 "index_name" => "Index name",
250 "name" => "Name",
251 "unique" => "Unique",
252 "seq_no" => "Seq. No.",
253 "emptied" => "has been emptied",
254 "dropped" => "has been dropped",
255 "renamed" => "has been renamed to",
256 "altered" => "has been altered successfully",
257 "inserted" => "inserted",
258 "deleted" => "deleted",
259 "affected" => "affected",
260 "blank_index" => "Index name must not be blank.",
261 "one_index" => "You must specify at least one index column.",
262 "docu" => "Documentation",
263 "license" => "License",
264 "proj_site" => "Project Site",
265 "bug_report" => "This may be a bug that needs to be reported at",
266 "return" => "Return",
267 "browse" => "Browse",
268 "fld" => "Field",
269 "fld_num" => "Number of Fields",
270 "fields" => "Fields",
271 "type" => "Type",
272 "operator" => "Operator",
273 "val" => "Value",
274 "update" => "Update",
275 "comments" => "Comments",
276
277 "specify_fields" => "You must specify the number of table fields.",
278 "specify_tbl" => "You must specify a table name.",
279 "specify_col" => "You must specify a column.",
280
281 "tbl_exists" => "Table of the same name already exists.",
282 "show" => "Show",
283 "show_rows" => "Showing %s row(s). ",
284 "showing" => "Showing",
285 "showing_rows" => "Showing rows",
286 "query_time" => "(Query took %s sec)",
287 "syntax_err" => "There is a problem with the syntax of your query (Query was not executed)",
288 "run_sql" => "Run SQL query/queries on database '%s'",
289 "recent_queries" => "Recent Queries",
290 "full_texts" => "Show full texts",
291 "no_full_texts" => "Shorten long texts",
292
293 "ques_empty" => "Are you sure you want to empty the table '%s'?",
294 "ques_drop" => "Are you sure you want to drop the table '%s'?",
295 "ques_drop_view" => "Are you sure you want to drop the view '%s'?",
296 "ques_del_rows" => "Are you sure you want to delete row(s) %s from table '%s'?",
297 "ques_del_db" => "Are you sure you want to delete the database '%s'?",
298 "ques_column_delete" => "Are you sure you want to delete column(s) %s from table '%s'?",
299 "ques_del_index" => "Are you sure you want to delete index '%s'?",
300 "ques_del_trigger" => "Are you sure you want to delete trigger '%s'?",
301 "ques_primarykey_add" => "Are you sure you want to add a primary key for the column(s) %s in table '%s'?",
302
303 "export_struct" => "Export with structure",
304 "export_data" => "Export with data",
305 "add_drop" => "Add DROP TABLE",
306 "add_transact" => "Add TRANSACTION",
307 "fld_terminated" => "Fields terminated by",
308 "fld_enclosed" => "Fields enclosed by",
309 "fld_escaped" => "Fields escaped by",
310 "fld_names" => "Field names in first row",
311 "rep_null" => "Replace NULL by",
312 "rem_crlf" => "Remove CRLF characters within fields",
313 "put_fld" => "Put field names in first row",
314 "null_represent" => "NULL represented by",
315 "import_suc" => "Import was successful.",
316 "import_into" => "Import into",
317 "import_f" => "File to import",
318 "rename_tbl" => "Rename table '%s' to",
319
320 "rows_records" => "row(s) starting from record # ",
321 "rows_aff" => "row(s) affected. ",
322
323 "as_a" => "as a",
324 "readonly_tbl" => "'%s' is a view, which means it is a SELECT statement treated as a read-only table. You may not edit or insert records.",
325 "chk_all" => "Check All",
326 "unchk_all" => "Uncheck All",
327 "with_sel" => "With Selected",
328
329 "no_tbl" => "No table in database.",
330 "no_chart" => "If you can read this, it means the chart could not be generated. The data you are trying to view may not be appropriate for a chart.",
331 "no_rows" => "There are no rows in the table for the range you selected.",
332 "no_sel" => "You did not select anything.",
333
334 "chart_type" => "Chart Type",
335 "chart_bar" => "Bar Chart",
336 "chart_pie" => "Pie Chart",
337 "chart_line" => "Line Chart",
338 "lbl" => "Labels",
339 "empty_tbl" => "This table is empty.",
340 "click" => "Click here",
341 "insert_rows" => "to insert rows.",
342 "restart_insert" => "Restart insertion with ",
343 "ignore" => "Ignore",
344 "func" => "Function",
345 "new_insert" => "Insert As New Row",
346 "save_ch" => "Save Changes",
347 "def_val" => "Default Value",
348 "prim_key" => "Primary Key",
349 "tbl_end" => "field(s) at end of table",
350 "query_used_table" => "Query used to create this table",
351 "query_used_view" => "Query used to create this view",
352 "create_index2" => "Create an index on",
353 "create_trigger2" => "Create a new trigger",
354 "new_fld" => "Adding new field(s) to table '%s'",
355 "add_flds" => "Add Fields",
356 "edit_col" => "Editing column '%s'",
357 "vac" => "Vacuum",
358 "vac_desc" => "Large databases sometimes need to be VACUUMed to reduce their footprint on the server. Click the button below to VACUUM the database '%s'.",
359 "event" => "Event",
360 "each_row" => "For Each Row",
361 "define_index" => "Define index properties",
362 "dup_val" => "Duplicate values",
363 "allow" => "Allowed",
364 "not_allow" => "Not Allowed",
365 "asc" => "Ascending",
366 "desc" => "Descending",
367 "warn0" => "You have been warned.",
368 "warn_passwd" => "You are using the default password, which can be dangerous. You can change it easily at the top of %s.",
369 "warn_dumbass" => "You didn't change the value dumbass ;-)",
370 "counting_skipped" => "Counting of records has been skipped for some tables because your database is comparably big and some tables don't have primary keys assigned to them so counting might be slow. Add a primary key to these tables or %sforce counting%s.",
371 "sel_state" => "Select Statement",
372 "delimit" => "Delimiter",
373 "back_top" => "Back to Top",
374 "choose_f" => "Choose File",
375 "instead" => "Instead of",
376 "define_in_col" => "Define index column(s)",
377
378 "delete_only_managed" => "You can only delete databases managed by this tool!",
379 "rename_only_managed" => "You can only rename databases managed by this tool!",
380 "db_moved_outside" => "You either tried to move the database into a directory where it cannot be managed anylonger, or the check if you did this failed because of missing rights.",
381 "extension_not_allowed" => "The extension you provided is not within the list of allowed extensions. Please use one of the following extensions",
382 "add_allowed_extension" => "You can add extensions to this list by adding your extension to \$allowed_extensions in the configuration.",
383 "directory_not_writable" => "The database-file itself is writable, but to write into it, the containing directory needs to be writable as well. This is because SQLite puts temporary files in there for locking.",
384 "tbl_inexistent" => "Table %s does not exist",
385
386 // errors that can happen when ALTER TABLE fails. You don't necessarily have to translate these.
387 "alter_failed" => "Altering of Table %s failed",
388 "alter_tbl_name_not_replacable" => "could not replace the table name with the temporary one",
389 "alter_no_def" => "no ALTER definition",
390 "alter_parse_failed" =>"failed to parse ALTER definition",
391 "alter_action_not_recognized" => "ALTER action could not be recognized",
392 "alter_no_add_col" => "no column to add detected in ALTER statement",
393 "alter_pattern_mismatch"=>"Pattern did not match on your original CREATE TABLE statement",
394 "alter_col_not_recognized" => "could not recognize new or old column name",
395 "alter_unknown_operation" => "Unknown ALTER operation!",
396
397 /* Help documentation */
398 "help_doc" => "Help Documentation",
399 "help1" => "SQLite Library Extensions",
400 "help1_x" => "%s uses PHP library extensions that allow interaction with SQLite databases. Currently, %s supports PDO, SQLite3, and SQLiteDatabase. Both PDO and SQLite3 deal with version 3 of SQLite, while SQLiteDatabase deals with version 2. So, if your PHP installation includes more than one SQLite library extension, PDO and SQLite3 will take precedence to make use of the better technology. However, if you have existing databases that are of version 2 of SQLite, %s will be forced to use SQLiteDatabase for only those databases. Not all databases need to be of the same version. During the database creation, however, the most advanced extension will be used.",
401 "help2" => "Creating a New Database",
402 "help2_x" => "When you create a new database, the name you entered will be appended with the appropriate file extension (.db, .db3, .sqlite, etc.) if you do not include it yourself. The database will be created in the directory you specified as the \$directory variable.",
403 "help3" => "Tables vs. Views",
404 "help3_x" => "On the main database page, there is a list of tables and views. Since views are read-only, certain operations will be disabled. These disabled operations will be apparent by their omission in the location where they should appear on the row for a view. If you want to change the data for a view, you need to drop that view and create a new view with the appropriate SELECT statement that queries other existing tables. For more information, see <a href='http://en.wikipedia.org/wiki/View_(database)' target='_blank'>http://en.wikipedia.org/wiki/View_(database)</a>",
405 "help4" => "Writing a Select Statement for a New View",
406 "help4_x" => "When you create a new view, you must write an SQL SELECT statement that it will use as its data. A view is simply a read-only table that can be accessed and queried like a regular table, except it cannot be modified through insertion, column editing, or row editing. It is only used for conveniently fetching data.",
407 "help5" => "Export Structure to SQL File",
408 "help5_x" => "During the process for exporting to an SQL file, you may choose to include the queries that create the table and columns.",
409 "help6" => "Export Data to SQL File",
410 "help6_x" => "During the process for exporting to an SQL file, you may choose to include the queries that populate the table(s) with the current records of the table(s).",
411 "help7" => "Add Drop Table to Exported SQL File",
412 "help7_x" => "During the process for exporting to an SQL file, you may choose to include queries to DROP the existing tables before adding them so that problems do not occur when trying to create tables that already exist.",
413 "help8" => "Add Transaction to Exported SQL File",
414 "help8_x" => "During the process for exporting to an SQL file, you may choose to wrap the queries around a TRANSACTION so that if an error occurs at any time during the importation process using the exported file, the database can be reverted to its previous state, preventing partially updated data from populating the database.",
415 "help9" => "Add Comments to Exported SQL File",
416 "help9_x" => "During the process for exporting to an SQL file, you may choose to include comments that explain each step of the process so that a human can better understand what is happening."
417
418);
419
420//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
421//there is no reason for the average user to edit anything below this comment
422//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
423
424//- Initialization
425
426// load optional configuration file
427$config_filename = './phpliteadmin.config.php';
428if (is_readable($config_filename)) {
429 include_once $config_filename;
430}
431
432//constants 1
433define("PROJECT", "phpLiteAdmin");
434define("VERSION", "1.9.6");
435define("PAGE", basename(__FILE__));
436define("FORCETYPE", false); //force the extension that will be used (set to false in almost all circumstances except debugging)
437define("SYSTEMPASSWORD", $password); // Makes things easier.
438define('PROJECT_URL','https://bitbucket.org/phpliteadmin/public');
439define('DONATE_URL','http://phpliteadmin.christosoft.de/donate.php');
440define('VERSION_CHECK_URL','https://phpliteadmin.christosoft.de/current_version.php');
441define('PROJECT_BUGTRACKER_LINK','<a href="https://bitbucket.org/phpliteadmin/public/issues?status=new&status=open" target="_blank">https://bitbucket.org/phpliteadmin/public/issues?status=new&status=open</a>');
442define('PROJECT_INSTALL_LINK','<a href="https://bitbucket.org/phpliteadmin/public/wiki/Installation" target="_blank">https://bitbucket.org/phpliteadmin/public/wiki/Installation</a>');
443
444// Resource output (css and javascript files)
445// we get out of the main code as soon as possible, without inizializing the session
446if (isset($_GET['resource'])) {
447 Resources::output($_GET['resource']);
448 exit();
449}
450
451// don't mess with this - required for the login session
452ini_set('session.cookie_httponly', '1');
453session_start();
454
455if($debug==true)
456{
457 ini_set("display_errors", 1);
458 error_reporting(E_STRICT | E_ALL);
459} else
460{
461 @ini_set("display_errors", 0);
462}
463
464// start the timer to record page load time
465$pageTimer = new MicroTimer();
466
467// load language file
468if($language != 'en') {
469 $temp_lang=$lang;
470 if(is_file('languages/lang_'.$language.'.php'))
471 include('languages/lang_'.$language.'.php');
472 elseif(is_file('lang_'.$language.'.php'))
473 include('lang_'.$language.'.php');
474 $lang = array_merge($temp_lang, $lang);
475 unset($temp_lang);
476}
477// version-number added so after updating, old session-data is not used anylonger
478// cookies names cannot contain symbols, except underscores
479define("COOKIENAME", preg_replace('/[^a-zA-Z0-9_]/', '_', $cookie_name . '_' . VERSION) );
480
481// stripslashes if MAGIC QUOTES is turned on
482// This is only a workaround. Please better turn off magic quotes!
483// This code is from http://php.net/manual/en/security.magicquotes.disabling.php
484if (get_magic_quotes_gpc()) {
485 $process = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
486 while (list($key, $val) = each($process)) {
487 foreach ($val as $k => $v) {
488 unset($process[$key][$k]);
489 if (is_array($v)) {
490 $process[$key][stripslashes($k)] = $v;
491 $process[] = &$process[$key][stripslashes($k)];
492 } else {
493 $process[$key][stripslashes($k)] = stripslashes($v);
494 }
495 }
496 }
497 unset($process);
498}
499
500
501//data types array
502$sqlite_datatypes = array("INTEGER", "REAL", "TEXT", "BLOB","NUMERIC","BOOLEAN","DATETIME");
503
504//available SQLite functions array (don't add anything here or there will be problems)
505$sqlite_functions = array("abs", "hex", "length", "lower", "ltrim", "random", "round", "rtrim", "trim", "typeof", "upper");
506
507//- Support functions
508
509//function that allows SQL delimiter to be ignored inside comments or strings
510function explode_sql($delimiter, $sql)
511{
512 $ign = array('"' => '"', "'" => "'", "/*" => "*/", "--" => "\n"); // Ignore sequences.
513 $out = array();
514 $last = 0;
515 $slen = strlen($sql);
516 $dlen = strlen($delimiter);
517 $i = 0;
518 while($i < $slen)
519 {
520 // Split on delimiter
521 if($slen - $i >= $dlen && substr($sql, $i, $dlen) == $delimiter)
522 {
523 array_push($out, substr($sql, $last, $i - $last));
524 $last = $i + $dlen;
525 $i += $dlen;
526 continue;
527 }
528 // Eat comments and string literals
529 foreach($ign as $start => $end)
530 {
531 $ilen = strlen($start);
532 if($slen - $i >= $ilen && substr($sql, $i, $ilen) == $start)
533 {
534 $i+=strlen($start);
535 $elen = strlen($end);
536 while($i < $slen)
537 {
538 if($slen - $i >= $elen && substr($sql, $i, $elen) == $end)
539 {
540 // SQL comment characters can be escaped by doubling the character. This recognizes and skips those.
541 if($start == $end && $slen - $i >= $elen*2 && substr($sql, $i, $elen*2) == $end.$end)
542 {
543 $i += $elen * 2;
544 continue;
545 }
546 else
547 {
548 $i += $elen;
549 continue 3;
550 }
551 }
552 $i++;
553 }
554 continue 2;
555 }
556 }
557 $i++;
558 }
559 if($last < $slen)
560 array_push($out, substr($sql, $last, $slen - $last));
561 return $out;
562}
563
564//function to scan entire directory tree and subdirectories
565function dir_tree($dir)
566{
567 $path = '';
568 $stack[] = $dir;
569 while($stack)
570 {
571 $thisdir = array_pop($stack);
572 if($dircont = scandir($thisdir))
573 {
574 $i=0;
575 while(isset($dircont[$i]))
576 {
577 if($dircont[$i] !== '.' && $dircont[$i] !== '..')
578 {
579 $current_file = $thisdir.DIRECTORY_SEPARATOR.$dircont[$i];
580 if(is_file($current_file))
581 {
582 $path[] = $thisdir.DIRECTORY_SEPARATOR.$dircont[$i];
583 }
584 elseif (is_dir($current_file))
585 {
586 $path[] = $thisdir.DIRECTORY_SEPARATOR.$dircont[$i];
587 $stack[] = $current_file;
588 }
589 }
590 $i++;
591 }
592 }
593 }
594 return $path;
595}
596
597//the function echo the help [?] links to the documentation
598function helpLink($name)
599{
600 global $lang;
601 return "<a href='?help=1' onclick='openHelp(\"".$name."\"); return false;' class='helpq' title='".$lang['help'].": ".$name."' target='_blank'><span>[?]</span></a>";
602}
603
604// function to encode value into HTML just like htmlentities, but with adjusted default settings
605function htmlencode($value, $flags=ENT_QUOTES, $encoding ="UTF-8")
606{
607 return htmlentities($value, $flags, $encoding);
608}
609
610// 22 August 2011: gkf added this function to support display of
611// default values in the form used to INSERT new data.
612function deQuoteSQL($s)
613{
614 return trim(trim($s), "'");
615}
616
617// reduce string chars
618function subString($str)
619{
620 global $charsNum;
621 if($charsNum > 10 && !$_SESSION[COOKIENAME.'fulltexts'] && strlen($str)>$charsNum)
622 {
623 $str = substr($str, 0, $charsNum).'...';
624 }
625 return $str;
626}
627
628// checks the (new) name of a database file
629function checkDbName($name)
630{
631 global $allowed_extensions;
632 $info = pathinfo($name);
633 if(isset($info['extension']) && !in_array($info['extension'], $allowed_extensions))
634 {
635 return false;
636 } else
637 {
638 return (!is_file($name) && !is_dir($name));
639 }
640
641}
642
643// check whether a path is a db managed by this tool
644// requires that $databases is already filled!
645// returns the key of the db if managed, false otherwise.
646function isManagedDB($path)
647{
648 global $databases;
649 foreach($databases as $db_key => $database)
650 {
651 if($path == $database['path'])
652 {
653 // a db we manage. Thats okay.
654 // return the key.
655 return $db_key;
656 }
657 }
658 // not a db we manage!
659 return false;
660}
661
662// from a typename of a colun, get the type of the column's affinty
663// see http://www.sqlite.org/datatype3.html section 2.1 for rules
664function get_type_affinity($type)
665{
666 if (preg_match("/INT/i", $type))
667 return "INTEGER";
668 else if (preg_match("/(?:CHAR|CLOB|TEXT)/i", $type))
669 return "TEXT";
670 else if (preg_match("/BLOB/i", $type) || $type=="")
671 return "NONE";
672 else if (preg_match("/(?:REAL|FLOA|DOUB)/i", $type))
673 return "REAL";
674 else
675 return "NUMERIC";
676}
677
678
679//- Check user authentication, login and logout
680$auth = new Authorization(); //create authorization object
681
682// check if user has attempted to log out
683if (isset($_POST['logout'])) {
684 $auth->revoke();
685 die(header ("Location: /index.php"));
686}
687
688// check if user has attempted to log in
689else if (isset($_POST['login']) && isset($_POST['password']))
690 $auth->attemptGrant($_POST['password'], isset($_POST['remember']));
691
692//- Actions on database files and bulk data
693if ($auth->isAuthorized())
694{
695
696 //- Create a new database
697 if(isset($_POST['new_dbname']))
698 {
699 if($_POST['new_dbname']=='')
700 {
701 // TODO: Display an error message (do NOT echo here. echo below in the html-body!)
702 }
703 else
704 {
705 $str = preg_replace('@[^\w-.]@','', $_POST['new_dbname']);
706 $dbname = $str;
707 $dbpath = $str;
708 if(checkDbName($dbname))
709 {
710 $tdata = array();
711 $tdata['name'] = $dbname;
712 $tdata['path'] = $directory.DIRECTORY_SEPARATOR.$dbpath;
713 $td = new Database($tdata);
714 $td->query("VACUUM");
715 } else
716 {
717 if(is_file($dbname) || is_dir($dbname)) $dbexists = true;
718 else $extension_not_allowed=true;
719 }
720 }
721 }
722
723 //- Scan a directory for databases
724 if($directory!==false)
725 {
726 if($directory[strlen($directory)-1]==DIRECTORY_SEPARATOR) //if user has a trailing slash in the directory, remove it
727 $directory = substr($directory, 0, strlen($directory)-1);
728
729 if(is_dir($directory)) //make sure the directory is valid
730 {
731 if($subdirectories===true)
732 $arr = dir_tree($directory);
733 else
734 $arr = scandir($directory);
735 $databases = array();
736 $j = 0;
737 for($i=0; $i<sizeof($arr); $i++) //iterate through all the files in the databases
738 {
739 if($subdirectories===false)
740 $arr[$i] = $directory.DIRECTORY_SEPARATOR.$arr[$i];
741
742 if(@!is_file($arr[$i])) continue;
743 $con = file_get_contents($arr[$i], NULL, NULL, 0, 60);
744 if(strpos($con, "** This file contains an SQLite 2.1 database **", 0)!==false || strpos($con, "SQLite format 3", 0)!==false)
745 {
746 $databases[$j]['path'] = $arr[$i];
747 if($subdirectories===false)
748 $databases[$j]['name'] = basename($arr[$i]);
749 else
750 $databases[$j]['name'] = $arr[$i];
751 $databases[$j]['writable'] = is_writable($databases[$j]['path']);
752 $databases[$j]['writable_dir'] = is_writable(dirname($databases[$j]['path']));
753 $databases[$j]['readable'] = is_readable($databases[$j]['path']);
754 $j++;
755 }
756 }
757 // 22 August 2011: gkf fixed bug #50.
758 sort($databases);
759 if(isset($tdata))
760 {
761 foreach($databases as $db_id => $database)
762 {
763 if($database['path'] == $tdata['path'])
764 {
765 $_SESSION[COOKIENAME.'currentDB'] = $database;
766 break;
767 }
768 }
769 }
770 }
771 else //the directory is not valid - display error and exit
772 {
773 echo "<div class='confirm' style='margin:20px;'>".$lang['not_dir']."</div>";
774 exit();
775 }
776 }
777 else
778 {
779 for($i=0; $i<sizeof($databases); $i++)
780 {
781 if(!file_exists($databases[$i]['path']))
782 continue; //skip if file not found ! - probably a warning can be displayed - later
783 $databases[$i]['writable'] = is_writable($databases[$i]['path']);
784 $databases[$i]['writable_dir'] = is_writable(dirname($databases[$i]['path']));
785 $databases[$i]['readable'] = is_readable($databases[$i]['path']);
786 }
787 sort($databases);
788 }
789 // we now have the $databases array set. Check whethet currentDB is a managed Db (is in this array)
790 if(isset($_SESSION[COOKIENAME.'currentDB']) && isManagedDB($_SESSION[COOKIENAME.'currentDB']['path']) === false)
791 unset($_SESSION[COOKIENAME.'currentDB']);
792
793 //- Delete an existing database
794 if(isset($_GET['database_delete']))
795 {
796 $dbpath = $_POST['database_delete'];
797 // check whether $dbpath really is a db we manage
798 $checkDB = isManagedDB($dbpath);
799 if($checkDB !== false)
800 {
801 unlink($dbpath);
802 unset($_SESSION[COOKIENAME.'currentDB']);
803 unset($databases[$checkDB]);
804 } else die($lang['err'].': '.$lang['delete_only_managed']);
805 }
806
807 //- Rename an existing database
808 if(isset($_GET['database_rename']))
809 {
810 $oldpath = $_POST['oldname'];
811 $newpath = $_POST['newname'];
812 $oldpath_parts = pathinfo($oldpath);
813 $newpath_parts = pathinfo($newpath);
814 // only rename?
815 $newpath = $oldpath_parts['dirname'].DIRECTORY_SEPARATOR.basename($_POST['newname']);
816 if($newpath != $_POST['newname'] && $subdirectories)
817 {
818 // it seems that the file should not only be renamed but additionally moved.
819 // we need to make sure it stays within $directory...
820 $new_realpath = realpath($newpath_parts['dirname']).DIRECTORY_SEPARATOR;
821 $directory_realpath = realpath($directory).DIRECTORY_SEPARATOR;
822 if(strpos($new_realpath, $directory_realpath)===0)
823 {
824 // its okay, the new directory is within $directory
825 $newpath = $_POST['newname'];
826 }
827 else die($lang['err'].': '.$lang['db_moved_outside']);
828 }
829
830 if(checkDbName($newpath))
831 {
832 $checkDB = isManagedDB($oldpath);
833 if($checkDB !==false )
834 {
835 rename($oldpath, $newpath);
836 $databases[$checkDB]['path'] = $newpath;
837 $databases[$checkDB]['name'] = basename($newpath);
838 $_SESSION[COOKIENAME.'currentDB'] = $databases[$checkDB];
839 $justrenamed = true;
840 }
841 else die($lang['err'].': '.$lang['rename_only_managed']);
842 }
843 else
844 {
845 if(is_file($newpath) || is_dir($newpath)) $dbexists = true;
846 else $extension_not_allowed = true;
847 }
848 }
849
850
851 //- Export (download a dump) an existing database
852 if(isset($_POST['export']))
853 {
854 $export_filename = str_replace(array("\r", "\n"), '',$_POST['filename']); // against http header injection (php < 5.1.2 only)
855 if($_POST['export_type']=="sql")
856 {
857 header('Content-Type: text/sql');
858 header('Content-Disposition: attachment; filename="'.$export_filename.'.'.$_POST['export_type'].'";');
859 if(isset($_POST['tables']))
860 $tables = $_POST['tables'];
861 else
862 {
863 $tables = array();
864 $tables[0] = $_POST['single_table'];
865 }
866 $drop = isset($_POST['drop']);
867 $structure = isset($_POST['structure']);
868 $data = isset($_POST['data']);
869 $transaction = isset($_POST['transaction']);
870 $comments = isset($_POST['comments']);
871 $db = new Database($_SESSION[COOKIENAME.'currentDB']);
872 echo $db->export_sql($tables, $drop, $structure, $data, $transaction, $comments);
873 }
874 else if($_POST['export_type']=="csv")
875 {
876 header("Content-type: application/csv");
877 header('Content-Disposition: attachment; filename="'.$export_filename.'.'.$_POST['export_type'].'";');
878 header("Pragma: no-cache");
879 header("Expires: 0");
880 if(isset($_POST['tables']))
881 $tables = $_POST['tables'];
882 else
883 {
884 $tables = array();
885 $tables[0] = $_POST['single_table'];
886 }
887 $field_terminate = $_POST['export_csv_fieldsterminated'];
888 $field_enclosed = $_POST['export_csv_fieldsenclosed'];
889 $field_escaped = $_POST['export_csv_fieldsescaped'];
890 $null = $_POST['export_csv_replacenull'];
891 $crlf = isset($_POST['export_csv_crlf']);
892 $fields_in_first_row = isset($_POST['export_csv_fieldnames']);
893 $db = new Database($_SESSION[COOKIENAME.'currentDB']);
894 echo $db->export_csv($tables, $field_terminate, $field_enclosed, $field_escaped, $null, $crlf, $fields_in_first_row);
895 }
896 exit();
897 }
898
899 //- Import a file into an existing database
900 if(isset($_POST['import']))
901 {
902 $db = new Database($_SESSION[COOKIENAME.'currentDB']);
903 $db->registerUserFunction($custom_functions);
904 if($_POST['import_type']=="sql")
905 {
906 $data = file_get_contents($_FILES["file"]["tmp_name"]);
907 $importSuccess = $db->import_sql($data);
908 }
909 else
910 {
911 $field_terminate = $_POST['import_csv_fieldsterminated'];
912 $field_enclosed = $_POST['import_csv_fieldsenclosed'];
913 $field_escaped = $_POST['import_csv_fieldsescaped'];
914 $null = $_POST['import_csv_replacenull'];
915 $fields_in_first_row = isset($_POST['import_csv_fieldnames']);
916 $importSuccess = $db->import_csv($_FILES["file"]["tmp_name"], $_POST['single_table'], $field_terminate, $field_enclosed, $field_escaped, $null, $fields_in_first_row);
917 }
918 }
919 //- Download (backup) a database file (as SQLite file, not as dump)
920 if(isset($_GET['download']) && isManagedDB($_GET['download'])!==false)
921 {
922 header("Content-type: application/octet-stream");
923 header('Content-Disposition: attachment; filename="'.basename($_GET['download']).'";');
924 header("Pragma: no-cache");
925 header("Expires: 0");
926 readfile($_GET['download']);
927 exit;
928 }
929}
930
931//- HTML: output starts here
932header('Content-Type: text/html; charset=utf-8');
933?>
934<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
935<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
936<head>
937<!-- Copyright <?php echo date("Y").' '.PROJECT.' ('.PROJECT_URL.')'; ?> -->
938<meta http-equiv='Content-Type' content='text/html; charset=UTF-8' />
939<link rel="shortcut icon" href="?resource=favicon" />
940<title><?php echo PROJECT ?></title>
941
942<?php
943//- HTML: css/theme include
944if(isset($_GET['theme'])) $theme = basename($_GET['theme']);
945
946// allow themes to be dropped in subfolder "themes"
947if(is_file('themes/'.$theme)) $theme = 'themes/'.$theme;
948
949if (file_exists($theme))
950 // an external stylesheet exists - import it
951 echo "<link href='{$theme}' rel='stylesheet' type='text/css' />", PHP_EOL;
952else
953 // only use the default stylesheet if an external one does not exist
954 echo "<link href='?resource=css' rel='stylesheet' type='text/css' />", PHP_EOL;
955
956// HTML: output help text, then exit
957if(isset($_GET['help']))
958{
959 //help section array
960 $help = array
961 (
962 $lang['help1'] => sprintf($lang['help1_x'], PROJECT, PROJECT, PROJECT), $lang['help2'] => $lang['help2_x'], $lang['help3'] => $lang['help3_x'],
963 $lang['help4'] => $lang['help4_x'], $lang['help5'] => $lang['help5_x'], $lang['help6'] => $lang['help6_x'],
964 $lang['help7'] => $lang['help7_x'], $lang['help8'] => $lang['help8_x'], $lang['help9'] => $lang['help9_x']
965 );
966 ?>
967 </head>
968 <body style="direction:<?php echo $lang['direction']; ?>;">
969 <div id='help_container'>
970 <?php
971 echo "<div class='help_list'>";
972 echo "<span style='font-size:18px;'>".PROJECT." v".VERSION." ".$lang['help_doc']."</span><br/><br/>";
973 foreach((array)$help as $key => $val)
974 {
975 echo "<a href='#".$key."'>".$key."</a><br/>";
976 }
977 echo "</div>";
978 echo "<br/><br/>";
979 foreach((array)$help as $key => $val)
980 {
981 echo "<div class='help_outer'>";
982 echo "<a class='headd' name='".$key."'>".$key."</a>";
983 echo "<div class='help_inner'>";
984 echo $val;
985 echo "</div>";
986 echo "<a class='help_top' href='#top'>".$lang['back_top']."</a>";
987 echo "</div>";
988 }
989 ?>
990 </div>
991 </body>
992 </html>
993 <?php
994 exit();
995}
996
997//- Javascript include
998?>
999<!-- JavaScript Support -->
1000<script type='text/javascript' src='?resource=javascript'></script>
1001</head>
1002<body style="direction:<?php echo $lang['direction']; ?>;">
1003<?php
1004if(ini_get("register_globals") == "on" || ini_get("register_globals")=="1") //check whether register_globals is turned on - if it is, we need to not continue
1005{
1006 echo "<div class='confirm' style='margin:20px;'>".$lang['bad_php_directive']."</div>";
1007 echo "</body></html>";
1008 exit();
1009}
1010
1011//- HTML: login screen if not authorized, exit
1012if(!$auth->isAuthorized())
1013{
1014 echo "<div id='loginBox'>";
1015 echo "<h1><span id='logo'>".PROJECT."</span> <span id='version'>v".VERSION."</span></h1>";
1016 echo "<div style='padding:15px; text-align:center;'>";
1017 if ($auth->isFailedLogin())
1018 echo "<span class='warning'>".$lang['passwd_incorrect']."</span><br/><br/>";
1019 echo "<form action='".PAGE."' method='post'>";
1020 echo $lang['passwd'].": <input type='password' name='password'/><br/>";
1021 echo "<label><input type='checkbox' name='remember' value='yes' checked='checked'/> ".$lang['remember']."</label><br/><br/>";
1022 echo "<input type='submit' value='".$lang['login']."' class='btn'/>";
1023 echo "<input type='hidden' name='login' value='true' />";
1024 echo "</form>";
1025 echo "</div>";
1026 echo "</div>";
1027 echo "<br/>";
1028 echo "<div style='text-align:center;'>";
1029 echo "<span style='font-size:11px;'>".$lang['powered']." <a href='".PROJECT_URL."' target='_blank' style='font-size:11px;'>".PROJECT."</a> | ";
1030 printf($lang['page_gen'], $pageTimer);
1031 echo "</span></div>";
1032 echo "</body></html>";
1033 exit();
1034}
1035
1036//- User is authorized, display the main application
1037
1038//- Select database (from session or first available)
1039if(!isset($_SESSION[COOKIENAME.'currentDB']) && count($databases)>0)
1040{
1041 //set the current database to the first existing one in the array (default)
1042 $_SESSION[COOKIENAME.'currentDB'] = reset($databases);
1043}
1044if(sizeof($databases)>0)
1045 $currentDB = $_SESSION[COOKIENAME.'currentDB'];
1046else // the database array is empty, offer to create a new database
1047{
1048 //- HTML: form to create a new database, exit
1049 if($directory!==false && is_writable($directory))
1050 {
1051 echo "<div class='confirm' style='margin:20px;'>";
1052 printf($lang['no_db'], PROJECT, PROJECT);
1053 echo "</div>";
1054 if(isset($extension_not_allowed))
1055 {
1056 echo "<div class='confirm' style='margin:10px 20px;'>";
1057 echo $lang['err'].': '.$lang['extension_not_allowed'].': ';
1058 echo implode(', ', array_map('htmlencode', $allowed_extensions));
1059 echo '<br />'.$lang['add_allowed_extension'];
1060 echo "</div><br/>";
1061 }
1062 echo "<fieldset style='margin:15px;'><legend><b>".$lang['db_create']."</b></legend>";
1063 echo "<form name='create_database' method='post' action='".PAGE."'>";
1064 echo "<input type='text' name='new_dbname' style='width:150px;'/> <input type='submit' value='".$lang['create']."' class='btn'/>";
1065 echo "</form>";
1066 echo "</fieldset>";
1067 }
1068 else
1069 {
1070 echo "<div class='confirm' style='margin:20px;'>";
1071 echo $lang['err'].": ".sprintf($lang['no_db2'], PROJECT);
1072 echo "</div><br/>";
1073 }
1074 exit();
1075}
1076
1077//- Switch to a different database with drop-down menu
1078if(isset($_POST['database_switch']))
1079{
1080 foreach($databases as $db_id => $database)
1081 {
1082 if($database['path'] == $_POST['database_switch'])
1083 {
1084 $_SESSION[COOKIENAME."currentDB"] = $database;
1085 break;
1086 }
1087 }
1088 $currentDB = $_SESSION[COOKIENAME.'currentDB'];
1089}
1090else if(isset($_GET['switchdb']))
1091{
1092 foreach($databases as $db_id => $database)
1093 {
1094 if($database['path'] == $_GET['switchdb'])
1095 {
1096 $_SESSION[COOKIENAME."currentDB"] = $database;
1097 break;
1098 }
1099 }
1100 $currentDB = $_SESSION[COOKIENAME.'currentDB'];
1101}
1102if(isset($_SESSION[COOKIENAME.'currentDB']) && in_array($_SESSION[COOKIENAME.'currentDB'], $databases))
1103 $currentDB = $_SESSION[COOKIENAME.'currentDB'];
1104
1105//- Open database (creates a Database object)
1106$db = new Database($currentDB); //create the Database object
1107$db->registerUserFunction($custom_functions);
1108
1109// collect parameters early, just once
1110$target_table = isset($_GET['table']) ? $_GET['table'] : null;
1111
1112//- Switch on $_GET['action'] for operations without output
1113if(isset($_GET['action']) && isset($_GET['confirm']))
1114{
1115 switch($_GET['action'])
1116 {
1117 //- Table actions
1118
1119 //- Create table (=table_create)
1120 case "table_create":
1121 $num = intval($_POST['rows']);
1122 $name = $_POST['tablename'];
1123 $primary_keys = array();
1124 for($i=0; $i<$num; $i++)
1125 {
1126 if($_POST[$i.'_field']!="" && isset($_POST[$i.'_primarykey']))
1127 {
1128 $primary_keys[] = $_POST[$i.'_field'];
1129 }
1130 }
1131 $query = "CREATE TABLE ".$db->quote($name)." (";
1132 for($i=0; $i<$num; $i++)
1133 {
1134 if($_POST[$i.'_field']!="")
1135 {
1136 $query .= $db->quote($_POST[$i.'_field'])." ";
1137 $query .= $_POST[$i.'_type']." ";
1138 if(isset($_POST[$i.'_primarykey']))
1139 {
1140 if(count($primary_keys)==1)
1141 {
1142 $query .= "PRIMARY KEY ";
1143 if(isset($_POST[$i.'_autoincrement']) && $db->getType() != "SQLiteDatabase")
1144 $query .= "AUTOINCREMENT ";
1145 }
1146 $query .= "NOT NULL ";
1147 }
1148 if(!isset($_POST[$i.'_primarykey']) && isset($_POST[$i.'_notnull']))
1149 $query .= "NOT NULL ";
1150 if($_POST[$i.'_defaultoption']!='defined' && $_POST[$i.'_defaultoption']!='none' && $_POST[$i.'_defaultoption']!='expr')
1151 $query .= "DEFAULT ".$_POST[$i.'_defaultoption']." ";
1152 elseif($_POST[$i.'_defaultoption']=='expr')
1153 $query .= "DEFAULT (".$_POST[$i.'_defaultvalue'].") ";
1154 elseif(isset($_POST[$i.'_defaultvalue']) && $_POST[$i.'_defaultoption']=='defined')
1155 {
1156 $typeAffinity = get_type_affinity($_POST[$i.'_type']);
1157 if(($typeAffinity=="INTEGER" || $typeAffinity=="REAL" || $typeAffinity=="NUMERIC") && is_numeric($_POST[$i.'_defaultvalue']))
1158 $query .= "DEFAULT ".$_POST[$i.'_defaultvalue']." ";
1159 else
1160 $query .= "DEFAULT ".$db->quote($_POST[$i.'_defaultvalue'])." ";
1161 }
1162 $query = substr($query, 0, sizeof($query)-2);
1163 $query .= ", ";
1164 }
1165 }
1166 if (count($primary_keys)>1)
1167 {
1168 $compound_key = "";
1169 foreach ($primary_keys as $primary_key)
1170 {
1171 $compound_key .= ($compound_key=="" ? "" : ", ") . $db->quote($primary_key);
1172 }
1173 $query .= "PRIMARY KEY (".$compound_key."), ";
1174 }
1175 $query = substr($query, 0, sizeof($query)-3);
1176 $query .= ")";
1177 $result = $db->query($query);
1178 if($result===false)
1179 $error = true;
1180 $completed = $lang['tbl']." '".htmlencode($_POST['tablename'])."' ".$lang['created'].".<br/><span style='font-size:11px;'>".htmlencode($query)."</span>";
1181 $backlinkParameters = "&action=column_view&table=".urlencode($name);
1182 break;
1183
1184 //- Empty table (=table_empty)
1185 case "table_empty":
1186 $query = "DELETE FROM ".$db->quote_id($_POST['tablename']);
1187 $result = $db->query($query);
1188 if($result===false)
1189 $error = true;
1190 $query = "VACUUM";
1191 $result = $db->query($query);
1192 if($result===false)
1193 $error = true;
1194 $completed = $lang['tbl']." '".htmlencode($_POST['tablename'])."' ".$lang['emptied'].".<br/><span style='font-size:11px;'>".htmlencode($query)."</span>";
1195 $backlinkParameters = "&action=row_view&table=".urlencode($name);
1196 break;
1197
1198 //- Create view (=view_create)
1199 case "view_create":
1200 $query = "CREATE VIEW ".$db->quote($_POST['viewname'])." AS ".$_POST['select'];
1201 $result = $db->query($query);
1202 if($result===false)
1203 $error = true;
1204 $completed = $lang['view']." '".htmlencode($_POST['viewname'])."' ".$lang['created'].".<br/><span style='font-size:11px;'>".htmlencode($query)."</span>";
1205 $backlinkParameters = "&action=column_view&table=".urlencode($_POST['viewname']);
1206 break;
1207
1208 //- Drop table (=table_drop)
1209 case "table_drop":
1210 $query = "DROP TABLE ".$db->quote_id($_POST['tablename']);
1211 $result=$db->query($query);
1212 if($result===false)
1213 $error = true;
1214 $completed = $lang['tbl']." '".htmlencode($_POST['tablename'])."' ".$lang['dropped'].".";
1215 $backlinkParameters = "";
1216 break;
1217
1218 //- Drop view (=view_drop)
1219 case "view_drop":
1220 $query = "DROP VIEW ".$db->quote_id($_POST['viewname']);
1221 $result=$db->query($query);
1222 if($result===false)
1223 $error = true;
1224 $completed = $lang['view']." '".htmlencode($_POST['viewname'])."' ".$lang['dropped'].".";
1225 $backlinkParameters = "";
1226 break;
1227
1228 //- Rename table (=table_rename)
1229 case "table_rename":
1230 $query = "ALTER TABLE ".$db->quote_id($_POST['oldname'])." RENAME TO ".$db->quote($_POST['newname']);
1231 if($db->getVersion()==3)
1232 $result = $db->query($query, true);
1233 else
1234 $result = $db->query($query, false);
1235 if($result===false)
1236 $error = true;
1237 $completed = $lang['tbl']." '".htmlencode($_POST['oldname'])."' ".$lang['renamed']." '".htmlencode($_POST['newname'])."'.<br/><span style='font-size:11px;'>".htmlencode($query)."</span>";
1238 $backlinkParameters = "&action=row_view&table=".urlencode($_POST['newname']);
1239 break;
1240
1241 //- Row actions
1242
1243 //- Create row (=row_create)
1244 case "row_create":
1245 $completed = "";
1246 $num = $_POST['numRows'];
1247 $fields = explode(":", $_POST['fields']);
1248 $z = 0;
1249
1250 $query = "PRAGMA table_info(".$db->quote_id($target_table).")";
1251 $result = $db->selectArray($query);
1252
1253 for($i=0; $i<$num; $i++)
1254 {
1255 if(!isset($_POST[$i.":ignore"]))
1256 {
1257 $query_cols = "";
1258 $query_vals = "";
1259 $all_default = true;
1260 for($j=0; $j<sizeof($fields); $j++)
1261 {
1262 // PHP replaces space with underscore
1263 $fields[$j] = str_replace(" ","_",$fields[$j]);
1264
1265 $null = isset($_POST[$i.":".$fields[$j]."_null"]);
1266 if(!$null)
1267 {
1268 if(!isset($_POST[$i.":".$fields[$j]]) && $debug)
1269 {
1270 echo "MISSING POST INDEX (".$i.":".$fields[$j].")<br><pre />";
1271 var_dump($_POST);
1272 echo "</pre><hr />";
1273 }
1274 $value = $_POST[$i.":".$fields[$j]];
1275 }
1276 else
1277 $value = "";
1278 if($value===$result[$j]['dflt_value'])
1279 {
1280 // if the value is the default value, skip it
1281 continue;
1282 } else
1283 $all_default = false;
1284 $query_cols .= $db->quote_id($fields[$j]).",";
1285
1286 $type = $result[$j]['type'];
1287 $typeAffinity = get_type_affinity($type);
1288 $function = $_POST["function_".$i."_".$fields[$j]];
1289 if($function!="")
1290 $query_vals .= $function."(";
1291 if(($typeAffinity=="TEXT" || $typeAffinity=="NONE") && !$null)
1292 $query_vals .= $db->quote($value);
1293 elseif(($typeAffinity=="INTEGER" || $typeAffinity=="REAL"|| $typeAffinity=="NUMERIC") && $value=="")
1294 $query_vals .= "NULL";
1295 elseif($null)
1296 $query_vals .= "NULL";
1297 else
1298 $query_vals .= $db->quote($value);
1299 if($function!="")
1300 $query_vals .= ")";
1301 $query_vals .= ",";
1302 }
1303 $query = "INSERT INTO ".$db->quote_id($target_table);
1304 if(!$all_default)
1305 {
1306 $query_cols = substr($query_cols, 0, strlen($query_cols)-1);
1307 $query_vals = substr($query_vals, 0, strlen($query_vals)-1);
1308
1309 $query.=" (". $query_cols . ") VALUES (". $query_vals. ")";
1310 } else {
1311 $query .= " DEFAULT VALUES";
1312 }
1313 $result1 = $db->query($query);
1314 if($result1===false)
1315 $error = true;
1316 $completed .= "<span style='font-size:11px;'>".htmlencode($query)."</span><br/>";
1317 $z++;
1318 }
1319 }
1320 $completed = $z." ".$lang['rows']." ".$lang['inserted'].".<br/><br/>".$completed;
1321 $backlinkParameters = "&action=column_view&table=".urlencode($target_table);
1322 break;
1323
1324 //- Delete row (=row_delete)
1325 case "row_delete":
1326 $pks = json_decode($_GET['pk']);
1327
1328 $query = "DELETE FROM ".$db->quote_id($target_table)." WHERE (".$db->wherePK($target_table,json_decode($pks[0])).")";
1329 for($i=1; $i<sizeof($pks); $i++)
1330 {
1331 $query .= " OR (".$db->wherePK($target_table,json_decode($pks[$i])).")";
1332 }
1333 $result = $db->query($query);
1334 if($result===false)
1335 $error = true;
1336 $completed = sizeof($pks)." ".$lang['rows']." ".$lang['deleted'].".<br/><span style='font-size:11px;'>".htmlencode($query)."</span>";
1337 $backlinkParameters = "&action=row_view&table=".urlencode($target_table);
1338 break;
1339
1340 //- Edit row (=row_edit)
1341 case "row_edit":
1342 $pks = json_decode($_GET['pk']);
1343 $fields = explode(":", $_POST['fieldArray']);
1344
1345 $z = 0;
1346
1347 $query = "PRAGMA table_info(".$db->quote_id($target_table).")";
1348 $result = $db->selectArray($query);
1349
1350 if(isset($_POST['new_row']))
1351 $completed = "";
1352 else
1353 $completed = sizeof($pks)." ".$lang['rows']." ".$lang['affected'].".<br/><br/>";
1354
1355 for($i=0; $i<sizeof($pks); $i++)
1356 {
1357 if(isset($_POST['new_row']))
1358 {
1359 $query_cols = "";
1360 $query_vals = "";
1361 $all_default = true;
1362 for($j=0; $j<sizeof($fields); $j++)
1363 {
1364 // PHP replaces space with underscore
1365 $fields[$j] = str_replace(" ","_",$fields[$j]);
1366
1367 $null = isset($_POST[$fields[$j]."_null"][$i]);
1368 if(!$null)
1369 {
1370 $value = $_POST[$fields[$j]][$i];
1371 }
1372 else
1373 $value = "";
1374 if($value===$result[$j]['dflt_value'])
1375 {
1376 // if the value is the default value, skip it
1377 continue;
1378 } else
1379 $all_default = false;
1380 $query_cols .= $db->quote_id($fields[$j]).",";
1381
1382 $type = $result[$j]['type'];
1383 $typeAffinity = get_type_affinity($type);
1384 $function = $_POST["function_".$fields[$j]][$i];
1385 if($function!="")
1386 $query_vals .= $function."(";
1387 if(($typeAffinity=="TEXT" || $typeAffinity=="NONE") && !$null)
1388 $query_vals .= $db->quote($value);
1389 elseif(($typeAffinity=="INTEGER" || $typeAffinity=="REAL"|| $typeAffinity=="NUMERIC") && $value=="")
1390 $query_vals .= "NULL";
1391 elseif($null)
1392 $query_vals .= "NULL";
1393 else
1394 $query_vals .= $db->quote($value);
1395 if($function!="")
1396 $query_vals .= ")";
1397 $query_vals .= ",";
1398 }
1399 $query = "INSERT INTO ".$db->quote_id($target_table);
1400 if(!$all_default)
1401 {
1402 $query_cols = substr($query_cols, 0, strlen($query_cols)-1);
1403 $query_vals = substr($query_vals, 0, strlen($query_vals)-1);
1404
1405 $query.=" (". $query_cols . ") VALUES (". $query_vals. ")";
1406 } else {
1407 $query .= " DEFAULT VALUES";
1408 }
1409 $result1 = $db->query($query);
1410 if($result1===false)
1411 $error = true;
1412 $z++;
1413 }
1414 else
1415 {
1416 $query = "UPDATE ".$db->quote_id($target_table)." SET ";
1417 for($j=0; $j<sizeof($fields); $j++)
1418 {
1419 $field_index = str_replace(" ","_",$fields[$j]);
1420 $function = $_POST["function_".$field_index][$i];
1421 $null = isset($_POST[$field_index."_null"][$i]);
1422 $query .= $db->quote_id($fields[$j])."=";
1423 if($function!="")
1424 $query .= $function."(";
1425 if($null)
1426 $query .= "NULL";
1427 else
1428 $query .= $db->quote($_POST[$field_index][$i]);
1429 if($function!="")
1430 $query .= ")";
1431 $query .= ", ";
1432 }
1433 $query = substr($query, 0, sizeof($query)-3);
1434 $query .= " WHERE ".$db->wherePK($target_table, json_decode($pks[$i]));
1435 $result1 = $db->query($query);
1436 if($result1===false)
1437 {
1438 $error = true;
1439 }
1440 }
1441 $completed .= "<span style='font-size:11px;'>".htmlencode($query)."</span><br/>";
1442 }
1443 if(isset($_POST['new_row']))
1444 $completed = $z." ".$lang['rows']." ".$lang['inserted'].".<br/><br/>".$completed;
1445 $backlinkParameters = "&action=row_view&table=".urlencode($target_table);
1446 break;
1447
1448 //- Column actions
1449
1450 //- Create column (=column_create)
1451 case "column_create":
1452 $num = intval($_POST['rows']);
1453 for($i=0; $i<$num; $i++)
1454 {
1455 if($_POST[$i.'_field']!="")
1456 {
1457 $query = "ALTER TABLE ".$db->quote_id($target_table)." ADD ".$db->quote($_POST[$i.'_field'])." ";
1458 $query .= $_POST[$i.'_type']." ";
1459 if(isset($_POST[$i.'_primarykey']))
1460 $query .= "PRIMARY KEY ";
1461 if(isset($_POST[$i.'_notnull']))
1462 $query .= "NOT NULL ";
1463 if($_POST[$i.'_defaultoption']!='defined' && $_POST[$i.'_defaultoption']!='none' && $_POST[$i.'_defaultoption']!='expr')
1464 $query .= "DEFAULT ".$_POST[$i.'_defaultoption']." ";
1465 elseif($_POST[$i.'_defaultoption']=='expr')
1466 $query .= "DEFAULT (".$_POST[$i.'_defaultvalue'].") ";
1467 elseif(isset($_POST[$i.'_defaultvalue']) && $_POST[$i.'_defaultoption']=='defined')
1468 {
1469 $typeAffinity = get_type_affinity($_POST[$i.'_type']);
1470 if(($typeAffinity=="INTEGER" || $typeAffinity=="REAL" || $typeAffinity=="NUMERIC") && is_numeric($_POST[$i.'_defaultvalue']))
1471 $query .= "DEFAULT ".$_POST[$i.'_defaultvalue']." ";
1472 else
1473 $query .= "DEFAULT ".$db->quote($_POST[$i.'_defaultvalue'])." ";
1474 }
1475 if($db->getVersion()==3 &&
1476 ($_POST[$i.'_defaultoption']=='defined' || $_POST[$i.'_defaultoption']=='none' || $_POST[$i.'_defaultoption']=='NULL')
1477 // Sqlite3 cannot add columns with default values that are not constant, so use AlterTable-workaround
1478 && !isset($_POST[$i.'_primarykey'])) // sqlite3 cannot add primary key columns
1479 $result = $db->query($query, true);
1480 else
1481 $result = $db->query($query, false);
1482 if($result===false)
1483 $error = true;
1484 }
1485 }
1486 $completed = $lang['tbl']." '".htmlencode($target_table)."' ".$lang['altered'].".";
1487 $backlinkParameters = "&action=column_view&table=".urlencode($target_table);
1488 break;
1489
1490 //- Delete column (=column_delete)
1491 case "column_delete":
1492 $pks = explode(":", $_GET['pk']);
1493 $query = "ALTER TABLE ".$db->quote_id($target_table).' DROP '.$db->quote_id($pks[0]);
1494 for($i=1; $i<sizeof($pks); $i++)
1495 {
1496 $query .= ", DROP ".$db->quote_id($pks[$i]);
1497 }
1498 $result = $db->query($query);
1499 if($result===false)
1500 $error = true;
1501 $completed = $lang['tbl']." '".htmlencode($target_table)."' ".$lang['altered'].".";
1502 $backlinkParameters = "&action=column_view&table=".urlencode($target_table);
1503 break;
1504
1505 //- Add a primary key (=primarykey_add)
1506 case "primarykey_add":
1507 $pks = explode(":", $_GET['pk']);
1508 $query = "ALTER TABLE ".$db->quote_id($target_table).' ADD PRIMARY KEY ('.$db->quote_id($pks[0]);
1509 for($i=1; $i<sizeof($pks); $i++)
1510 {
1511 $query .= ", ".$db->quote_id($pks[$i]);
1512 }
1513 $query .= ")";
1514 $result = $db->query($query);
1515 if($result===false)
1516 $error = true;
1517 $completed = $lang['tbl']." '".htmlencode($target_table)."' ".$lang['altered'].".";
1518 $backlinkParameters = "&action=column_view&table=".urlencode($target_table);
1519 break;
1520
1521 //- Edit column (=column_edit)
1522 case "column_edit":
1523 $query = "ALTER TABLE ".$db->quote_id($target_table).' CHANGE '.$db->quote_id($_POST['oldvalue'])." ".$db->quote($_POST['0_field'])." ".$_POST['0_type'];
1524 $result = $db->query($query);
1525 if($result===false)
1526 $error = true;
1527 $completed = $lang['tbl']." '".htmlencode($target_table)."' ".$lang['altered'].".";
1528 $backlinkParameters = "&action=column_view&table=".urlencode($target_table);
1529 break;
1530
1531 //- Delete trigger (=trigger_delete)
1532 case "trigger_delete":
1533 $query = "DROP TRIGGER ".$db->quote_id($_GET['pk']);
1534 $result = $db->query($query);
1535 if($result===false)
1536 $error = true;
1537 $completed = $lang['trigger']." '".htmlencode($_GET['pk'])."' ".$lang['deleted'].".<br/><span style='font-size:11px;'>".htmlencode($query)."</span>";
1538 $backlinkParameters = "&action=column_view&table=".urlencode($target_table);
1539 break;
1540
1541 //- Delete index (=index_delete)
1542 case "index_delete":
1543 $query = "DROP INDEX ".$db->quote_id($_GET['pk']);
1544 $result = $db->query($query);
1545 if($result===false)
1546 $error = true;
1547 $completed = $lang['index']." '".htmlencode($_GET['pk'])."' ".$lang['deleted'].".<br/><span style='font-size:11px;'>".htmlencode($query)."</span>";
1548 $backlinkParameters = "&action=column_view&table=".urlencode($target_table);
1549 break;
1550
1551 //- Create trigger (=trigger_create)
1552 case "trigger_create":
1553 $str = "CREATE TRIGGER ".$db->quote($_POST['trigger_name']);
1554 if($_POST['beforeafter']!="")
1555 $str .= " ".$_POST['beforeafter'];
1556 $str .= " ".$_POST['event']." ON ".$db->quote_id($target_table);
1557 if(isset($_POST['foreachrow']))
1558 $str .= " FOR EACH ROW";
1559 if($_POST['whenexpression']!="")
1560 $str .= " WHEN ".$_POST['whenexpression'];
1561 $str .= " BEGIN";
1562 $str .= " ".$_POST['triggersteps'];
1563 $str .= " END";
1564 $query = $str;
1565 $result = $db->query($query);
1566 if($result===false)
1567 $error = true;
1568 $completed = $lang['trigger']." ".$lang['created'].".<br/><span style='font-size:11px;'>".htmlencode($query)."</span>";
1569 $backlinkParameters = "&action=column_view&table=".urlencode($target_table);
1570 break;
1571
1572 //- Create index (=index_create)
1573 case "index_create":
1574 $num = $_POST['num'];
1575 if($_POST['name']=="")
1576 {
1577 $completed = $lang['blank_index'];
1578 }
1579 else if($_POST['0_field']=="")
1580 {
1581 $completed = $lang['one_index'];
1582 }
1583 else
1584 {
1585 $str = "CREATE ";
1586 if($_POST['duplicate']=="no")
1587 $str .= "UNIQUE ";
1588 $str .= "INDEX ".$db->quote($_POST['name'])." ON ".$db->quote_id($target_table)." (";
1589 $str .= $db->quote_id($_POST['0_field']).$_POST['0_order'];
1590 for($i=1; $i<$num; $i++)
1591 {
1592 if($_POST[$i.'_field']!="")
1593 $str .= ", ".$db->quote_id($_POST[$i.'_field']).$_POST[$i.'_order'];
1594 }
1595 $str .= ")";
1596 $query = $str;
1597 $result = $db->query($query);
1598 if($result===false)
1599 $error = true;
1600 $completed = $lang['index']." ".$lang['created'].".<br/><span style='font-size:11px;'>".htmlencode($query)."</span>";
1601 }
1602 $backlinkParameters = "&action=column_view&table=".urlencode($target_table);
1603 break;
1604 }
1605}
1606
1607// are we working on a view? let's check once here
1608$target_table_type = $target_table ? $db->getTypeOfTable($target_table) : null;
1609
1610//- HTML: sidebar
1611echo '<table class="body_tbl" width="100%" border="0" cellspacing="0" cellpadding="0"><tr><td valign="top" class="left_td" style="width:100px; padding:9px 2px 9px 9px;">';
1612echo "<div id='leftNav'>";
1613echo "<h1><a href='".PAGE."'>";
1614echo "<span id='logo'>".PROJECT."</span> <span id='version'>v".VERSION."</span>";
1615echo "</a></h1>";
1616echo "<div id='headerlinks'>";
1617echo "<a href='javascript:void' onclick='openHelp(\"top\");'>".$lang['docu']."</a> | ";
1618echo "<a href='http://www.gnu.org/licenses/gpl.html' target='_blank'>".$lang['license']."</a> | ";
1619echo "<a href='".PROJECT_URL."' target='_blank'>".$lang['proj_site']."</a>";
1620echo "</div>";
1621
1622//- HTML: database list
1623echo "<fieldset style='margin:15px;'><legend><b>".$lang['db_ch']."</b></legend>";
1624if(sizeof($databases)<10) //if there aren't a lot of databases, just show them as a list of links instead of drop down menu
1625{
1626 $i=0;
1627 foreach($databases as $database)
1628 {
1629 $i++;
1630 echo '[' . ($database['readable'] ? 'r':' ' ) . ($database['writable'] && $database['writable_dir'] ? 'w':' ' ) . '] ';
1631 if($database == $_SESSION[COOKIENAME.'currentDB'])
1632 echo "<a href='?switchdb=".urlencode($database['path'])."' class='active_db'>".htmlencode($database['name'])."</a> (<a href='?download=".urlencode($database['path'])."' title='".$lang['backup']."'>↓</a>)";
1633 else
1634 echo "<a href='?switchdb=".urlencode($database['path'])."'>".htmlencode($database['name'])."</a> (<a href='?download=".urlencode($database['path'])."' title='".$lang['backup']."'>↓</a>)";
1635 if($i<sizeof($databases))
1636 echo "<br/>";
1637 }
1638}
1639else //there are a lot of databases - show a drop down menu
1640{
1641 echo "<form action='".PAGE."' method='post'>";
1642 echo "<select name='database_switch'>";
1643 foreach($databases as $database)
1644 {
1645 $perms_string = htmlencode('[' . ($database['readable'] ? 'r':' ' ) . ($database['writable'] && $database['writable_dir'] ? 'w':' ' ) . '] ');
1646 if($database == $_SESSION[COOKIENAME.'currentDB'])
1647 echo "<option value='".htmlencode($database['path'])."' selected='selected'>".$perms_string.htmlencode($database['name'])."</option>";
1648 else
1649 echo "<option value='".htmlencode($database['path'])."'>".$perms_string.htmlencode($database['name'])."</option>";
1650 }
1651 echo "</select> ";
1652 echo "<input type='submit' value='".$lang['go']."' class='btn'>";
1653 echo "</form>";
1654}
1655echo "</fieldset>";
1656echo "<fieldset style='margin:15px;'><legend>";
1657echo "<a href='".PAGE."'";
1658if (!$target_table)
1659 echo " class='active_table'";
1660echo ">".htmlencode($currentDB['name'])."</a>";
1661echo "</legend>";
1662
1663//- HTML: table list
1664$query = "SELECT type, name FROM sqlite_master WHERE type='table' OR type='view' ORDER BY name";
1665$result = $db->selectArray($query);
1666$j=0;
1667for($i=0; $i<sizeof($result); $i++)
1668{
1669 if(substr($result[$i]['name'], 0, 7)!="sqlite_" && $result[$i]['name']!="")
1670 {
1671 echo "<span class='sidebar_table'>[".$lang[$result[$i]['type']=='table'?'tbl':'view']."]</span> ";
1672 echo "<a href='?action=row_view&table=".urlencode($result[$i]['name'])."'";
1673 if ($target_table == $result[$i]['name'])
1674 echo " class='active_table'";
1675 echo ">".htmlencode($result[$i]['name'])."</a><br/>";
1676 $j++;
1677 }
1678}
1679if($j==0)
1680 echo $lang['no_tbl'];
1681echo "</fieldset>";
1682
1683//- HTML: form to create a new database
1684if($directory!==false && is_writable($directory))
1685{
1686 echo "<fieldset style='margin:15px;'><legend><b>".$lang['db_create']."</b> ".helpLink($lang['help2'])."</legend>";
1687 echo "<form name='create_database' method='post' action='".PAGE."'>";
1688 echo "<input type='text' name='new_dbname' style='width:150px;'/> <input type='submit' value='".$lang['create']."' class='btn'/>";
1689 echo "</form>";
1690 echo "</fieldset>";
1691}
1692
1693echo "<div style='text-align:center;'>";
1694echo "<form action='".PAGE."' method='post'>";
1695echo "<input type='submit' value='".$lang['logout']."' name='logout' class='btn'/>";
1696echo "</form>";
1697echo "</div>";
1698echo "</div>";
1699echo '</td><td valign="top" id="main_column" class="right_td" style="padding:9px 2px 9px 9px;">';
1700
1701//- HTML: breadcrumb navigation
1702echo "<a href='".PAGE."'>".htmlencode($currentDB['name'])."</a>";
1703if ($target_table)
1704 echo " → <a href='?table=".urlencode($target_table)."&action=row_view'>".htmlencode($target_table)."</a>";
1705echo "<br/><br/>";
1706
1707//- HTML: confirmation panel
1708//if the user has performed some action, show the resulting message
1709if(isset($_GET['confirm']))
1710{
1711 echo "<div id='main'>";
1712 echo "<div class='confirm'>";
1713 if(isset($error) && $error) //an error occured during the action, so show an error message
1714 echo $lang['err'].": ".$db->getError()."<br/>".$lang['bug_report'].' '.PROJECT_BUGTRACKER_LINK;
1715 else //action was performed successfully - show success message
1716 echo $completed;
1717 echo "</div>";
1718 if($_GET['action']=="row_delete" || $_GET['action']=="row_create" || $_GET['action']=="row_edit")
1719 echo "<br/><br/><a href='?table=".urlencode($target_table)."&action=row_view'>".$lang['return']."</a>";
1720 else if($_GET['action']=="column_create" || $_GET['action']=="column_delete" || $_GET['action']=="column_edit" || $_GET['action']=="index_create" || $_GET['action']=="index_delete" || $_GET['action']=="trigger_delete" || $_GET['action']=="trigger_create")
1721 echo "<br/><br/><a href='?table=".urlencode($target_table)."&action=column_view'>".$lang['return']."</a>";
1722 else
1723 echo "<br/><br/><a href='".PAGE.(isset($backlinkParameters)?"?".$backlinkParameters:'')."'>".$lang['return']."</a>";
1724 echo "</div>";
1725}
1726
1727//- Show the various tab views for a table
1728if(!isset($_GET['confirm']) && $target_table && isset($_GET['action']) && ($_GET['action']=="table_export" || $_GET['action']=="table_import" || $_GET['action']=="table_sql" || $_GET['action']=="row_view" || $_GET['action']=="row_create" || $_GET['action']=="column_view" || $_GET['action']=="table_rename" || $_GET['action']=="table_search" || $_GET['action']=="table_triggers"))
1729{
1730 //- HTML: tabs for tables
1731 if($target_table_type == 'table')
1732 {
1733 echo "<a href='?table=".urlencode($target_table)."&action=row_view' ";
1734 if($_GET['action']=="row_view")
1735 echo "class='tab_pressed'";
1736 else
1737 echo "class='tab'";
1738 echo ">".$lang['browse']."</a>";
1739 echo "<a href='?table=".urlencode($target_table)."&action=column_view' ";
1740 if($_GET['action']=="column_view")
1741 echo "class='tab_pressed'";
1742 else
1743 echo "class='tab'";
1744 echo ">".$lang['struct']."</a>";
1745 echo "<a href='?table=".urlencode($target_table)."&action=table_sql' ";
1746 if($_GET['action']=="table_sql")
1747 echo "class='tab_pressed'";
1748 else
1749 echo "class='tab'";
1750 echo ">".$lang['sql']."</a>";
1751 echo "<a href='?table=".urlencode($target_table)."&action=table_search' ";
1752 if($_GET['action']=="table_search")
1753 echo "class='tab_pressed'";
1754 else
1755 echo "class='tab'";
1756 echo ">".$lang['srch']."</a>";
1757 echo "<a href='?table=".urlencode($target_table)."&action=row_create' ";
1758 if($_GET['action']=="row_create")
1759 echo "class='tab_pressed'";
1760 else
1761 echo "class='tab'";
1762 echo ">".$lang['insert']."</a>";
1763 echo "<a href='?table=".urlencode($target_table)."&action=table_export' ";
1764 if($_GET['action']=="table_export")
1765 echo "class='tab_pressed'";
1766 else
1767 echo "class='tab'";
1768 echo ">".$lang['export']."</a>";
1769 echo "<a href='?table=".urlencode($target_table)."&action=table_import' ";
1770 if($_GET['action']=="table_import")
1771 echo "class='tab_pressed'";
1772 else
1773 echo "class='tab'";
1774 echo ">".$lang['import']."</a>";
1775 echo "<a href='?table=".urlencode($target_table)."&action=table_rename' ";
1776 if($_GET['action']=="table_rename")
1777 echo "class='tab_pressed'";
1778 else
1779 echo "class='tab'";
1780 echo ">".$lang['rename']."</a>";
1781 echo "<a href='?action=table_empty&table=".urlencode($target_table)."' ";
1782 echo "class='tab empty'";
1783 echo ">".$lang['empty']."</a>";
1784 echo "<a href='?action=table_drop&table=".urlencode($target_table)."' ";
1785 echo "class='tab drop'";
1786 echo ">".$lang['drop']."</a>";
1787 echo "<div style='clear:both;'></div>";
1788 }
1789 else
1790 //- HTML: tabs for views
1791 {
1792 echo "<a href='?table=".urlencode($target_table)."&action=row_view' ";
1793 if($_GET['action']=="row_view")
1794 echo "class='tab_pressed'";
1795 else
1796 echo "class='tab'";
1797 echo ">".$lang['browse']."</a>";
1798 echo "<a href='?table=".urlencode($target_table)."&action=column_view' ";
1799 if($_GET['action']=="column_view")
1800 echo "class='tab_pressed'";
1801 else
1802 echo "class='tab'";
1803 echo ">".$lang['struct']."</a>";
1804 echo "<a href='?table=".urlencode($target_table)."&action=table_sql' ";
1805 if($_GET['action']=="table_sql")
1806 echo "class='tab_pressed'";
1807 else
1808 echo "class='tab'";
1809 echo ">".$lang['sql']."</a>";
1810 echo "<a href='?table=".urlencode($target_table)."&action=table_search' ";
1811 if($_GET['action']=="table_search")
1812 echo "class='tab_pressed'";
1813 else
1814 echo "class='tab'";
1815 echo ">".$lang['srch']."</a>";
1816 echo "<a href='?table=".urlencode($target_table)."&action=table_export' ";
1817 if($_GET['action']=="table_export")
1818 echo "class='tab_pressed'";
1819 else
1820 echo "class='tab'";
1821 echo ">".$lang['export']."</a>";
1822 echo "<a href='?action=view_drop&table=".urlencode($target_table)."' ";
1823 echo "class='tab drop'";
1824 echo ">".$lang['drop']."</a>";
1825 echo "<div style='clear:both;'></div>";
1826 }
1827}
1828
1829//- Switch on $_GET['action'] for operations with output
1830if(isset($_GET['action']) && !isset($_GET['confirm']))
1831{
1832 echo "<div id='main'>";
1833 switch($_GET['action'])
1834 {
1835 //- Table actions
1836
1837 //- Create table (=table_create)
1838 case "table_create":
1839 $query = "SELECT name FROM sqlite_master WHERE type='table' AND name=".$db->quote($_POST['tablename']);
1840 $results = $db->selectArray($query);
1841 if(sizeof($results)>0)
1842 $exists = true;
1843 else
1844 $exists = false;
1845 echo "<h2>".$lang['create_tbl'].": '".htmlencode($_POST['tablename'])."'</h2>";
1846 if($_POST['tablefields']=="" || intval($_POST['tablefields'])<=0)
1847 echo $lang['specify_fields'];
1848 else if($_POST['tablename']=="")
1849 echo $lang['specify_tbl'];
1850 else if($exists)
1851 echo $lang['tbl_exists'];
1852 else
1853 {
1854 $num = intval($_POST['tablefields']);
1855 $name = $_POST['tablename'];
1856 echo "<form action='?action=table_create&confirm=1' method='post'>";
1857 echo "<input type='hidden' name='tablename' value='".htmlencode($name)."'/>";
1858 echo "<input type='hidden' name='rows' value='".$num."'/>";
1859 echo "<table border='0' cellpadding='2' cellspacing='1' class='viewTable'>";
1860 echo "<tr>";
1861 $headings = array($lang['fld'], $lang['type'], $lang['prim_key']);
1862 if($db->getType() != "SQLiteDatabase") $headings[] = $lang['autoincrement'];
1863 $headings[] = $lang['not_null'];
1864 $headings[] = $lang['def_val'];
1865 for($k=0; $k<count($headings); $k++)
1866 echo "<td class='tdheader'>" . $headings[$k] . "</td>";
1867 echo "</tr>";
1868
1869 for($i=0; $i<$num; $i++)
1870 {
1871 $tdWithClass = "<td class='td" . ($i%2 ? "1" : "2") . "'>";
1872 echo "<tr>";
1873 echo $tdWithClass;
1874 echo "<input type='text' name='".$i."_field' style='width:200px;'/>";
1875 echo "</td>";
1876 echo $tdWithClass;
1877 echo "<select name='".$i."_type' id='i".$i."_type' onchange='toggleAutoincrement(".$i.");'>";
1878 foreach ($sqlite_datatypes as $t) {
1879 echo "<option value='".htmlencode($t)."'>".htmlencode($t)."</option>";
1880 }
1881 echo "</select>";
1882 echo "</td>";
1883 echo $tdWithClass;
1884 echo "<label><input type='checkbox' name='".$i."_primarykey' id='i".$i."_primarykey' onclick='toggleNull(".$i."); toggleAutoincrement(".$i.");'/> ".$lang['yes']."</label>";
1885 echo "</td>";
1886 if($db->getType() != "SQLiteDatabase")
1887 {
1888 echo $tdWithClass;
1889 echo "<label><input type='checkbox' name='".$i."_autoincrement' id='i".$i."_autoincrement'/> ".$lang['yes']."</label>";
1890 echo "</td>";
1891 }
1892 echo $tdWithClass;
1893 echo "<label><input type='checkbox' name='".$i."_notnull' id='i".$i."_notnull'/> ".$lang['yes']."</label>";
1894 echo "</td>";
1895 echo $tdWithClass;
1896 echo "<select name='".$i."_defaultoption' id='i".$i."_defaultoption' onchange=\"if(this.value!='defined' && this.value!='expr') document.getElementById('i".$i."_defaultvalue').value='';\">";
1897 echo "<option value='none'>".$lang['none']."</option><option value='defined'>".$lang['as_defined'].":</option><option>NULL</option><option>CURRENT_TIME</option><option>CURRENT_DATE</option><option>CURRENT_TIMESTAMP</option><option value='expr'>".$lang['expression'].":</option>";
1898 echo "</select>";
1899 echo "<input type='text' name='".$i."_defaultvalue' id='i".$i."_defaultvalue' style='width:100px;' onchange=\"if(document.getElementById('i".$i."_defaultoption').value!='expr') document.getElementById('i".$i."_defaultoption').value='defined';\"/>";
1900 echo "</td>";
1901 echo "</tr>";
1902 }
1903 echo "<tr>";
1904 echo "<td class='tdheader' style='text-align:right;' colspan='6'>";
1905 echo "<input type='submit' value='".$lang['create']."' class='btn'/> ";
1906 echo "<a href='".PAGE."'>".$lang['cancel']."</a>";
1907 echo "</td>";
1908 echo "</tr>";
1909 echo "</table>";
1910 echo "</form>";
1911 if($db->getType() != "SQLiteDatabase") echo "<script type='text/javascript'>window.onload=initAutoincrement;</script>";
1912 }
1913 break;
1914
1915 //- Perform SQL query on table (=table_sql)
1916 case "table_sql":
1917 $isSelect = false;
1918 if(isset($_POST['query']) && $_POST['query']!="")
1919 {
1920 $delimiter = $_POST['delimiter'];
1921 $queryStr = $_POST['queryval'];
1922 //save the queries in history if necessary
1923 if($maxSavedQueries!=0 && $maxSavedQueries!=false)
1924 {
1925 if(!isset($_SESSION['query_history']))
1926 $_SESSION['query_history'] = array();
1927 $_SESSION['query_history'][md5(strtolower($queryStr))] = $queryStr;
1928 if(sizeof($_SESSION['query_history']) > $maxSavedQueries)
1929 array_shift($_SESSION['query_history']);
1930 }
1931 $query = explode_sql($delimiter, $queryStr); //explode the query string into individual queries based on the delimiter
1932
1933 for($i=0; $i<sizeof($query); $i++) //iterate through the queries exploded by the delimiter
1934 {
1935 if(str_replace(" ", "", str_replace("\n", "", str_replace("\r", "", $query[$i])))!="") //make sure this query is not an empty string
1936 {
1937 $queryTimer = new MicroTimer();
1938 $result = $db->selectArray($query[$i], "assoc");
1939 $queryTimer->stop();
1940
1941 echo "<div class='confirm'>";
1942 echo "<b>";
1943
1944 if($result !== NULL)
1945 {
1946
1947 if(sizeof($result)>0 || $db->getAffectedRows()==0)
1948 {
1949 printf($lang['show_rows'], sizeof($result));
1950 }
1951 if($db->getAffectedRows()>0 || sizeof($result)==0)
1952 {
1953 echo $db->getAffectedRows()." ".$lang['rows_aff']." ";
1954 }
1955 printf($lang['query_time'], $queryTimer);
1956 echo "</b><br/>";
1957 }
1958 else
1959 {
1960 echo $lang['err'].": ".$db->getError()."</b><br/>";
1961 }
1962
1963 echo "<span style='font-size:11px;'>".htmlencode($query[$i])."</span>";
1964 echo "</div><br/>";
1965 if(sizeof($result)>0)
1966 {
1967 $headers = array_keys($result[0]);
1968
1969 echo "<table border='0' cellpadding='2' cellspacing='1' class='viewTable'>";
1970 echo "<tr>";
1971 for($j=0; $j<sizeof($headers); $j++)
1972 {
1973 echo "<td class='tdheader'>";
1974 echo htmlencode($headers[$j]);
1975 echo "</td>";
1976 }
1977 echo "</tr>";
1978 for($j=0; $j<sizeof($result); $j++)
1979 {
1980 $tdWithClass = "<td class='td".($j%2 ? "1" : "2")."'>";
1981 echo "<tr>";
1982 for($z=0; $z<sizeof($headers); $z++)
1983 {
1984 echo $tdWithClass;
1985 if($result[$j][$headers[$z]]==="")
1986 echo " ";
1987 elseif($result[$j][$headers[$z]]===NULL)
1988 echo "<i class='null'>NULL</i>";
1989 else
1990 echo htmlencode(subString($result[$j][$headers[$z]]));
1991 echo "</td>";
1992 }
1993 echo "</tr>";
1994 }
1995 echo "</table><br/><br/>";
1996 }
1997 }
1998 }
1999 }
2000 else
2001 {
2002 $delimiter = ";";
2003 $queryStr = "SELECT * FROM ".$db->quote_id($target_table)." WHERE 1";
2004 }
2005
2006 echo "<fieldset>";
2007 echo "<legend><b>".sprintf($lang['run_sql'],htmlencode($db->getName()))."</b></legend>";
2008 echo "<form action='?table=".urlencode($target_table)."&action=table_sql' method='post'>";
2009 if(isset($_SESSION['query_history']) && sizeof($_SESSION['query_history'])>0)
2010 {
2011 echo "<b>".$lang['recent_queries']."</b><ul>";
2012 foreach($_SESSION['query_history'] as $key => $value)
2013 echo "<li><a onclick='document.getElementById(\"queryval\").value = this.textContent' href='#'>".htmlencode($value)."</a></li>";
2014 echo "</ul><br/><br/>";
2015 }
2016 echo "<div style='float:left; width:70%;'>";
2017 echo "<textarea style='width:97%; height:300px;' name='queryval' id='queryval' cols='50' rows='8'>".htmlencode($queryStr)."</textarea>";
2018 echo "</div>";
2019 echo "<div style='float:left; width:28%; padding-left:10px;'>";
2020 echo $lang['fields']."<br/>";
2021 echo "<select multiple='multiple' style='width:100%;' id='fieldcontainer'>";
2022 $query = "PRAGMA table_info(".$db->quote_id($target_table).")";
2023 $result = $db->selectArray($query);
2024 for($i=0; $i<sizeof($result); $i++)
2025 {
2026 echo "<option value='".htmlencode($result[$i][1])."'>".htmlencode($result[$i][1])."</option>";
2027 }
2028 echo "</select>";
2029 echo "<input type='button' value='<<' onclick='moveFields();' class='btn'/>";
2030 echo "</div>";
2031 echo "<div style='clear:both;'></div>";
2032 echo $lang['delimit']." <input type='text' name='delimiter' value='".htmlencode($delimiter)."' style='width:50px;'/> ";
2033 echo "<input type='submit' name='query' value='".$lang['go']."' class='btn'/>";
2034 echo "</form>";
2035 echo "</fieldset>";
2036 break;
2037
2038 //- Empty table (=table_empty)
2039 case "table_empty":
2040 echo "<form action='?action=table_empty&confirm=1' method='post'>";
2041 echo "<input type='hidden' name='tablename' value='".htmlencode($target_table)."'/>";
2042 echo "<div class='confirm'>";
2043 echo sprintf($lang['ques_empty'], htmlencode($target_table))."<br/><br/>";
2044 echo "<input type='submit' value='".$lang['confirm']."' class='btn'/> ";
2045 echo "<a href='".PAGE."'>".$lang['cancel']."</a>";
2046 echo "</div>";
2047 break;
2048
2049 //- Drop table (=table_drop)
2050 case "table_drop":
2051 echo "<form action='?action=table_drop&confirm=1' method='post'>";
2052 echo "<input type='hidden' name='tablename' value='".htmlencode($target_table)."'/>";
2053 echo "<div class='confirm'>";
2054 echo sprintf($lang['ques_drop'], htmlencode($target_table))."<br/><br/>";
2055 echo "<input type='submit' value='".$lang['confirm']."' class='btn'/> ";
2056 echo "<a href='".PAGE."'>".$lang['cancel']."</a>";
2057 echo "</div>";
2058 break;
2059
2060 //- Drop view (=view_drop)
2061 case "view_drop":
2062 echo "<form action='?action=view_drop&confirm=1' method='post'>";
2063 echo "<input type='hidden' name='viewname' value='".htmlencode($target_table)."'/>";
2064 echo "<div class='confirm'>";
2065 echo sprintf($lang['ques_drop_view'], htmlencode($target_table))."<br/><br/>";
2066 echo "<input type='submit' value='".$lang['confirm']."' class='btn'/> ";
2067 echo "<a href='".PAGE."'>".$lang['cancel']."</a>";
2068 echo "</div>";
2069 break;
2070
2071 //- Export table (=table_export)
2072 case "table_export":
2073 echo "<form method='post' action='".PAGE."'>";
2074 echo "<fieldset style='float:left; width:260px; margin-right:20px;'><legend><b>".$lang['export']."</b></legend>";
2075 echo "<input type='hidden' value='".htmlencode($target_table)."' name='single_table'/>";
2076 echo "<label><input type='radio' name='export_type' checked='checked' value='sql' onclick='toggleExports(\"sql\");'/> ".$lang['sql']."</label>";
2077 echo "<br/><label><input type='radio' name='export_type' value='csv' onclick='toggleExports(\"csv\");'/> ".$lang['csv']."</label>";
2078 echo "</fieldset>";
2079
2080 echo "<fieldset style='float:left; max-width:350px;' id='exportoptions_sql'><legend><b>".$lang['options']."</b></legend>";
2081 echo "<label><input type='checkbox' checked='checked' name='structure'/> ".$lang['export_struct']."</label> ".helpLink($lang['help5'])."<br/>";
2082 echo "<label><input type='checkbox' checked='checked' name='data'/> ".$lang['export_data']."</label> ".helpLink($lang['help6'])."<br/>";
2083 echo "<label><input type='checkbox' name='drop'/> ".$lang['add_drop']."</label> ".helpLink($lang['help7'])."<br/>";
2084 echo "<label><input type='checkbox' checked='checked' name='transaction'/> ".$lang['add_transact']."</label> ".helpLink($lang['help8'])."<br/>";
2085 echo "<label><input type='checkbox' checked='checked' name='comments'/> ".$lang['comments']."</label> ".helpLink($lang['help9'])."<br/>";
2086 echo "</fieldset>";
2087
2088 echo "<fieldset style='float:left; max-width:350px; display:none;' id='exportoptions_csv'><legend><b>".$lang['options']."</b></legend>";
2089 echo "<div style='float:left;'>".$lang['fld_terminated']."</div>";
2090 echo "<input type='text' value=';' name='export_csv_fieldsterminated' style='float:right;'/>";
2091 echo "<div style='clear:both;'></div>";
2092 echo "<div style='float:left;'>".$lang['fld_enclosed']."</div>";
2093 echo "<input type='text' value='\"' name='export_csv_fieldsenclosed' style='float:right;'/>";
2094 echo "<div style='clear:both;'></div>";
2095 echo "<div style='float:left;'>".$lang['fld_escaped']."</div>";
2096 echo "<input type='text' value='\' name='export_csv_fieldsescaped' style='float:right;'/>";
2097 echo "<div style='clear:both;'></div>";
2098 echo "<div style='float:left;'>".$lang['rep_null']."</div>";
2099 echo "<input type='text' value='NULL' name='export_csv_replacenull' style='float:right;'/>";
2100 echo "<div style='clear:both;'></div>";
2101 echo "<label><input type='checkbox' name='export_csv_crlf'/> ".$lang['rem_crlf']."</label><br/>";
2102 echo "<label><input type='checkbox' checked='checked' name='export_csv_fieldnames'/> ".$lang['put_fld']."</label>";
2103 echo "</fieldset>";
2104
2105 echo "<div style='clear:both;'></div>";
2106 echo "<br/><br/>";
2107 echo "<fieldset><legend><b>".$lang['save_as']."</b></legend>";
2108 $file = pathinfo($db->getPath());
2109 $name = $file['filename'];
2110 echo "<input type='text' name='filename' value='".htmlencode($name)."_".htmlencode($target_table)."_".date("Y-m-d").".dump' style='width:400px;'/> <input type='submit' name='export' value='".$lang['export']."' class='btn'/>";
2111 echo "</fieldset>";
2112 echo "</form>";
2113 echo "<div class='confirm' style='margin-top: 2em'>".sprintf($lang['backup_hint'], "<a href='?download=".urlencode($currentDB['path'])."' title='".$lang['backup']."'>".$lang["backup_hint_linktext"]."</a>")."</div>";
2114 break;
2115
2116 //- Import table (=table_import)
2117 case "table_import":
2118 if(isset($_POST['import']))
2119 {
2120 echo "<div class='confirm'>";
2121 if($importSuccess===true)
2122 echo $lang['import_suc'];
2123 else
2124 echo $lang['err'].': '.$importSuccess;
2125 echo "</div><br/>";
2126 }
2127 echo "<form method='post' action='?table=".urlencode($target_table)."&action=table_import' enctype='multipart/form-data'>";
2128 echo "<fieldset style='float:left; width:260px; margin-right:20px;'><legend><b>".$lang['import_into']." ".htmlencode($target_table)."</b></legend>";
2129 echo "<label><input type='radio' name='import_type' checked='checked' value='sql' onclick='toggleImports(\"sql\");'/> ".$lang['sql']."</label>";
2130 echo "<br/><label><input type='radio' name='import_type' value='csv' onclick='toggleImports(\"csv\");'/> ".$lang['csv']."</label>";
2131 echo "</fieldset>";
2132
2133 echo "<fieldset style='float:left; max-width:350px;' id='importoptions_sql'><legend><b>".$lang['options']."</b></legend>";
2134 echo $lang['no_opt'];
2135 echo "</fieldset>";
2136
2137 echo "<fieldset style='float:left; max-width:350px; display:none;' id='importoptions_csv'><legend><b>".$lang['options']."</b></legend>";
2138 echo "<input type='hidden' value='".htmlencode($target_table)."' name='single_table'/>";
2139 echo "<div style='float:left;'>".$lang['fld_terminated']."</div>";
2140 echo "<input type='text' value=';' name='import_csv_fieldsterminated' style='float:right;'/>";
2141 echo "<div style='clear:both;'>";
2142 echo "<div style='float:left;'>".$lang['fld_enclosed']."</div>";
2143 echo "<input type='text' value='\"' name='import_csv_fieldsenclosed' style='float:right;'/>";
2144 echo "<div style='clear:both;'>";
2145 echo "<div style='float:left;'>".$lang['fld_escaped']."</div>";
2146 echo "<input type='text' value='\' name='import_csv_fieldsescaped' style='float:right;'/>";
2147 echo "<div style='clear:both;'>";
2148 echo "<div style='float:left;'>".$lang['rep_null']."</div>";
2149 echo "<input type='text' value='NULL' name='import_csv_replacenull' style='float:right;'/>";
2150 echo "<div style='clear:both;'>";
2151 echo "<label><input type='checkbox' checked='checked' name='import_csv_fieldnames'/> ".$lang['fld_names']."</label>";
2152 echo "</fieldset>";
2153
2154 echo "<div style='clear:both;'></div>";
2155 echo "<br/><br/>";
2156
2157 echo "<fieldset><legend><b>".$lang['import_f']."</b></legend>";
2158 echo "<input type='file' value='".$lang['choose_f']."' name='file' style='background-color:transparent; border-style:none;'/> <input type='submit' value='".$lang['import']."' name='import' class='btn'/>";
2159 echo "</fieldset>";
2160 break;
2161
2162 //- Rename table (=table_rename)
2163 case "table_rename":
2164 echo "<form action='?action=table_rename&confirm=1' method='post'>";
2165 echo "<input type='hidden' name='oldname' value='".htmlencode($target_table)."'/>";
2166 printf($lang['rename_tbl'], htmlencode($target_table));
2167 echo " <input type='text' name='newname' style='width:200px;'/> <input type='submit' value='".$lang['rename']."' name='rename' class='btn'/>";
2168 echo "</form>";
2169 break;
2170
2171 //- Search table (=table_search)
2172 case "table_search":
2173 $searchValues = array();
2174 if(isset($_GET['done']))
2175 {
2176 $query = "PRAGMA table_info(".$db->quote_id($target_table).")";
2177 $result = $db->selectArray($query);
2178 $primary_key = $db->getPrimaryKey($target_table);
2179 $j = 0;
2180 $arr = array();
2181 for($i=0; $i<sizeof($result); $i++)
2182 {
2183 $field = $result[$i][1];
2184 $field_index = str_replace(" ","_",$field);
2185 $operator = $_POST[$field_index.":operator"];
2186 $value = $_POST[$field_index];
2187 if($value!="" || $operator=="!= ''" || $operator=="= ''")
2188 {
2189 if($operator=="= ''" || $operator=="!= ''")
2190 $arr[$j] = $db->quote_id($field)." ".$operator;
2191
2192 else{
2193 if($operator == "LIKE%"){
2194 $operator = "LIKE";
2195 if(!preg_match('/(^%)|(%$)/', $value)) $value = '%'.$value.'%';
2196 }
2197 $searchValues[$field] = $value;
2198 $arr[$j] = $db->quote_id($field)." ".$operator." ".$db->quote($value);
2199 }
2200 $j++;
2201 }
2202 }
2203 $query = "SELECT *";
2204 // select the primary key column(s) last (ROWID if there is no PK).
2205 // this will be used to identify rows, e.g. when editing/deleting rows
2206 $primary_key = $db->getPrimaryKey($target_table);
2207 foreach($primary_key as $pk)
2208 {
2209 $query.= ', '.$db->quote_id($pk);
2210 $query.= ', typeof('.$db->quote_id($pk).')';
2211 }
2212 $query .= " FROM ".$db->quote_id($target_table);
2213 $whereTo = '';
2214 if(sizeof($arr)>0)
2215 {
2216 $whereTo .= " WHERE ".$arr[0];
2217 for($i=1; $i<sizeof($arr); $i++)
2218 {
2219 $whereTo .= " AND ".$arr[$i];
2220 }
2221 }
2222 $query .= $whereTo;
2223 $query_disp = "SELECT * FROM " . $db->quote_id($target_table) . $whereTo;
2224 $queryTimer = new MicroTimer();
2225 $arr = $db->selectArray($query);
2226 $queryTimer->stop();
2227
2228 echo "<div class='confirm'>";
2229 echo "<b>";
2230 if($arr!==false)
2231 {
2232 $affected = sizeof($arr);
2233 echo $lang['showing']." ".$affected." ".$lang['rows'].". ";
2234 printf($lang['query_time'], $queryTimer);
2235 echo "</b><br/>";
2236 }
2237 else
2238 {
2239 echo $lang['err'].": ".$db->getError().".</b><br/>".$lang['bug_report'].' '.PROJECT_BUGTRACKER_LINK.'<br/>';
2240 }
2241 echo "<span style='font-size:11px;'>".htmlencode($query_disp)."</span>";
2242 echo "</div><br/>";
2243
2244 if(sizeof($arr)>0)
2245 {
2246 if($target_table_type == 'view')
2247 {
2248 echo sprintf($lang['readonly_tbl'], htmlencode($target_table))." <a href='http://en.wikipedia.org/wiki/View_(database)' target='_blank'>http://en.wikipedia.org/wiki/View_(database)</a>";
2249 echo "<br/><br/>";
2250 }
2251
2252 echo "<table border='0' cellpadding='2' cellspacing='1' class='viewTable'>";
2253 echo "<tr>";
2254 if($target_table_type == 'table')
2255 {
2256 echo "<td colspan='2' class='tdheader' style='text-align:center'>";
2257 #todo: make sure the search keywords are kept
2258 #echo "<a href='?action=table_search&done=1&table=".$target_table."&fulltexts=".($_SESSION[COOKIENAME.'fulltexts']?0:1)."' title='".$lang[($_SESSION[COOKIENAME.'fulltexts']?'no_full_texts':'full_texts')]."'>";
2259 #echo "<b>&".($_SESSION[COOKIENAME.'fulltexts']?'r':'l')."arr;</b> T <b>&".($_SESSION[COOKIENAME.'fulltexts']?'l':'r')."arr;</b></a>";
2260 echo "</td>";
2261 }
2262
2263 $header = array();
2264 for($j=0; $j<sizeof($result); $j++)
2265 {
2266 $headers[$j]=$result[$j]['name'];
2267 echo "<td class='tdheader'>";
2268 echo htmlencode($headers[$j]);
2269 echo "</td>";
2270 }
2271 echo "</tr>";
2272
2273 $pkFirstCol = sizeof($result)+1;
2274 for($j=0; $j<sizeof($arr); $j++)
2275 {
2276 // -g-> $pk will always be the last columns in each row of the array because we are doing "SELECT *, PK_1, typeof(PK_1), PK2, typeof(PK_2), ... FROM ..."
2277 $pk_arr = array();
2278 for($col = $pkFirstCol; array_key_exists($col, $arr[$j]); $col=$col+2)
2279 {
2280 // in $col we have the type and in $col-1 the value
2281 if($arr[$j][$col]=='integer' || $arr[$j][$col]=='real')
2282 // json encode as int or float, not string
2283 $pk_arr[] = $arr[$j][$col-1]+0;
2284 else
2285 // encode as json string
2286 $pk_arr[] = $arr[$j][$col-1];
2287 }
2288 $pk = json_encode($pk_arr);
2289 $tdWithClass = "<td class='td".($j%2 ? "1" : "2")."'>";
2290 echo "<tr>";
2291 if($target_table_type == 'table')
2292 {
2293 echo $tdWithClass."<a href='?table=".urlencode($target_table)."&action=row_editordelete&pk=".urlencode($pk)."&type=edit' title='".$lang['edit']."' class='edit'><span>".$lang['edit']."</span></a></td>";
2294 echo $tdWithClass."<a href='?table=".urlencode($target_table)."&action=row_editordelete&pk=".urlencode($pk)."&type=delete' title='".$lang['del']."' class='delete'><span>".$lang['del']."</span></a></td>";
2295 }
2296 for($z=0; $z<sizeof($result); $z++)
2297 {
2298 echo $tdWithClass;
2299 $fldResult = $arr[$j][$headers[$z]];
2300 if(isset($searchValues[$headers[$z]]))
2301 {
2302 $foundVal = str_replace('%', '', $searchValues[$headers[$z]]);
2303 $fldResult = str_ireplace($foundVal, '[fnd]'.$foundVal.'[/fnd]', $fldResult);
2304 // we replace with [fnd] first because we need to htmlencode _afterwards_ without breaking the found-markers
2305 // htmlencoing _before_ would mean we might highlight stuff inside of htmlcode thus breaking it
2306 }
2307 echo str_replace(array('[fnd]', '[/fnd]'), array('<u class="found">', '</u>'), htmlencode($fldResult));
2308 echo "</td>";
2309 }
2310 echo "</tr>";
2311 }
2312 echo "</table><br/><br/>";
2313 }
2314
2315 echo "<a href='?table=".urlencode($target_table)."&action=table_search'>".$lang['srch_again']."</a>";
2316 }
2317 else
2318 {
2319 $query = "PRAGMA table_info(".$db->quote_id($target_table).")";
2320 $result = $db->selectArray($query);
2321
2322 echo "<form action='?table=".urlencode($target_table)."&action=table_search&done=1' method='post'>";
2323
2324 echo "<table border='0' cellpadding='2' cellspacing='1' class='viewTable'>";
2325 echo "<tr>";
2326 echo "<td class='tdheader'>".$lang['fld']."</td>";
2327 echo "<td class='tdheader'>".$lang['type']."</td>";
2328 echo "<td class='tdheader'>".$lang['operator']."</td>";
2329 echo "<td class='tdheader'>".$lang['val']."</td>";
2330 echo "</tr>";
2331
2332 for($i=0; $i<sizeof($result); $i++)
2333 {
2334 $field = $result[$i][1];
2335 $type = $result[$i]['type'];
2336 $typeAffinity = get_type_affinity($type);
2337 $tdWithClass = "<td class='td".($i%2 ? "1" : "2")."'>";
2338 $tdWithClassLeft = "<td class='td".($i%2 ? "1" : "2")."' style='text-align:left;'>";
2339 echo "<tr>";
2340 echo $tdWithClassLeft;
2341 echo htmlencode($field);
2342 echo "</td>";
2343 echo $tdWithClassLeft;
2344 echo htmlencode($type);
2345 echo "</td>";
2346 echo $tdWithClassLeft;
2347 echo "<select name='".htmlencode($field).":operator' onchange='checkLike(\"".htmlencode($field)."_search\", this.options[this.selectedIndex].value); '>";
2348 echo "<option value='='>=</option>";
2349 if($typeAffinity=="INTEGER" || $typeAffinity=="REAL" || $typeAffinity=="NUMERIC")
2350 {
2351 echo "<option value='>'>></option>";
2352 echo "<option value='>='>>=</option>";
2353 echo "<option value='<'><</option>";
2354 echo "<option value='<='><=</option>";
2355 }
2356 else if($typeAffinity=="TEXT" || $typeAffinity=="NONE")
2357 {
2358 echo "<option value='= '''>= ''</option>";
2359 echo "<option value='!= '''>!= ''</option>";
2360 }
2361 echo "<option value='!='>!=</option>";
2362 if($typeAffinity=="TEXT" || $typeAffinity=="NONE")
2363 echo "<option value='LIKE' selected='selected'>LIKE</option>";
2364 else
2365 echo "<option value='LIKE'>LIKE</option>";
2366 echo "<option value='LIKE%'>LIKE %...%</option>";
2367 echo "<option value='NOT LIKE'>NOT LIKE</option>";
2368 echo "</select>";
2369 echo "</td>";
2370 echo $tdWithClassLeft;
2371 if($typeAffinity=="INTEGER" || $typeAffinity=="REAL" || $typeAffinity=="NUMERIC")
2372 echo "<input type='text' id='".htmlencode($field)."_search' name='".htmlencode($field)."'/>";
2373 else
2374 echo "<textarea id='".htmlencode($field)."_search' name='".htmlencode($field)."' rows='1' cols='60'></textarea>";
2375 echo "</td>";
2376 echo "</tr>";
2377 }
2378 echo "<tr>";
2379 echo "<td class='tdheader' style='text-align:right;' colspan='4'>";
2380 echo "<input type='submit' value='".$lang['srch']."' class='btn'/>";
2381 echo "</td>";
2382 echo "</tr>";
2383 echo "</table>";
2384 echo "</form>";
2385 }
2386 break;
2387
2388 //- Row actions
2389
2390 //- View row (=row_view)
2391 case "row_view":
2392 if(!isset($_POST['startRow']))
2393 $_POST['startRow'] = 0;
2394
2395 if(isset($_POST['numRows']))
2396 $_SESSION[COOKIENAME.'numRows'] = $_POST['numRows'];
2397
2398 if(!isset($_SESSION[COOKIENAME.'numRows']))
2399 $_SESSION[COOKIENAME.'numRows'] = $rowsNum;
2400
2401 if(isset($_GET['fulltexts']))
2402 $_SESSION[COOKIENAME.'fulltexts'] = $_GET['fulltexts'];
2403
2404 if(!isset($_SESSION[COOKIENAME.'fulltexts']))
2405 $_SESSION[COOKIENAME.'fulltexts'] = false;
2406
2407 if(isset($_SESSION[COOKIENAME.'currentTable']) && $_SESSION[COOKIENAME.'currentTable']!=$target_table)
2408 {
2409 unset($_SESSION[COOKIENAME.'sortRows']);
2410 unset($_SESSION[COOKIENAME.'orderRows']);
2411 }
2412 if(isset($_POST['viewtype']))
2413 {
2414 $_SESSION[COOKIENAME.'viewtype'] = $_POST['viewtype'];
2415 }
2416
2417 $rowCount = $db->numRows($target_table);
2418 $lastPage = intval($rowCount / $_SESSION[COOKIENAME.'numRows']);
2419 $remainder = intval($rowCount % $_SESSION[COOKIENAME.'numRows']);
2420 if($remainder==0)
2421 $remainder = $_SESSION[COOKIENAME.'numRows'];
2422
2423 //- HTML: pagination buttons
2424 echo "<div style=''>";
2425 //previous button
2426 if($_POST['startRow']>0)
2427 {
2428 echo "<div style='float:left;'>";
2429 echo "<form action='?action=row_view&table=".urlencode($target_table)."' method='post'>";
2430 echo "<input type='hidden' name='startRow' value='0'/>";
2431 echo "<input type='hidden' name='numRows' value='".$_SESSION[COOKIENAME.'numRows']."'/> ";
2432 echo "<input type='submit' value='←←' name='previous' class='btn'/> ";
2433 echo "</form>";
2434 echo "</div>";
2435 echo "<div style='float:left; overflow:hidden; margin-right:20px;'>";
2436 echo "<form action='?action=row_view&table=".urlencode($target_table)."' method='post'>";
2437 echo "<input type='hidden' name='startRow' value='".max(0,intval($_POST['startRow']-$_SESSION[COOKIENAME.'numRows']))."'/>";
2438 echo "<input type='hidden' name='numRows' value='".$_SESSION[COOKIENAME.'numRows']."'/> ";
2439 echo "<input type='submit' value='←' name='previous_full' class='btn'/> ";
2440 echo "</form>";
2441 echo "</div>";
2442 }
2443
2444 //show certain number buttons
2445 echo "<div style='float:left;'>";
2446 echo "<form action='?action=row_view&table=".urlencode($target_table)."' method='post'>";
2447 echo "<input type='submit' value='".$lang['show']." : ' name='show' class='btn'/> ";
2448 echo "<input type='text' name='numRows' style='width:50px;' value='".$_SESSION[COOKIENAME.'numRows']."'/> ";
2449 echo $lang['rows_records'];
2450
2451 if(intval($_POST['startRow']+$_SESSION[COOKIENAME.'numRows']) < $rowCount)
2452 echo "<input type='text' name='startRow' style='width:90px;' value='".intval($_POST['startRow']+$_SESSION[COOKIENAME.'numRows'])."'/>";
2453 else
2454 echo "<input type='text' name='startRow' style='width:90px;' value='0'/> ";
2455 echo $lang['as_a'];
2456 echo " <select name='viewtype'>";
2457 if(!isset($_SESSION[COOKIENAME.'viewtype']) || $_SESSION[COOKIENAME.'viewtype']=="table")
2458 {
2459 echo "<option value='table' selected='selected'>".$lang['tbl']."</option>";
2460 echo "<option value='chart'>".$lang['chart']."</option>";
2461 }
2462 else
2463 {
2464 echo "<option value='table'>".$lang['tbl']."</option>";
2465 echo "<option value='chart' selected='selected'>".$lang['chart']."</option>";
2466 }
2467 echo "</select>";
2468 echo "</form>";
2469 echo "</div>";
2470
2471 //next button
2472 if(intval($_POST['startRow']+$_SESSION[COOKIENAME.'numRows'])<$rowCount)
2473 {
2474 echo "<div style='float:left; margin-left:20px; '>";
2475 echo "<form action='?action=row_view&table=".urlencode($target_table)."' method='post'>";
2476 echo "<input type='hidden' name='startRow' value='".intval($_POST['startRow']+$_SESSION[COOKIENAME.'numRows'])."'/>";
2477 echo "<input type='hidden' name='numRows' value='".$_SESSION[COOKIENAME.'numRows']."'/> ";
2478 echo "<input type='submit' value='→' name='next' class='btn'/> ";
2479 echo "</form>";
2480 echo "</div>";
2481 echo "<div style='float:left; '>";
2482 echo "<form action='?action=row_view&table=".urlencode($target_table)."' method='post'>";
2483 echo "<input type='hidden' name='startRow' value='".intval($rowCount-$remainder)."'/>";
2484 echo "<input type='hidden' name='numRows' value='".$_SESSION[COOKIENAME.'numRows']."'/> ";
2485 echo "<input type='submit' value='→→' name='next_full' class='btn'/> ";
2486 echo "</form>";
2487 echo "</div>";
2488 }
2489 echo "<div style='clear:both;'></div>";
2490 echo "</div>";
2491
2492 //- Query execution
2493 if(!isset($_GET['sort']))
2494 $_GET['sort'] = NULL;
2495 if(!isset($_GET['order']))
2496 $_GET['order'] = NULL;
2497
2498 $numRows = $_SESSION[COOKIENAME.'numRows'];
2499 $startRow = $_POST['startRow'];
2500 if(isset($_GET['sort']))
2501 {
2502 $_SESSION[COOKIENAME.'sortRows'] = $_GET['sort'];
2503 $_SESSION[COOKIENAME.'currentTable'] = $target_table;
2504 }
2505 if(isset($_GET['order']))
2506 {
2507 $_SESSION[COOKIENAME.'orderRows'] = $_GET['order'];
2508 $_SESSION[COOKIENAME.'currentTable'] = $target_table;
2509 }
2510 $_SESSION[COOKIENAME.'numRows'] = $numRows;
2511 $query = "SELECT * ";
2512 // select the primary key column(s) last (ROWID if there is no PK).
2513 // this will be used to identify rows, e.g. when editing/deleting rows
2514 $primary_key = $db->getPrimaryKey($target_table);
2515 foreach($primary_key as $pk)
2516 {
2517 $query.= ', '.$db->quote_id($pk);
2518 $query.= ', typeof('.$db->quote_id($pk).')';
2519 }
2520 $query .= " FROM ".$db->quote_id($target_table);
2521 $queryDisp = "SELECT * FROM ".$db->quote_id($target_table);
2522 $queryAdd = "";
2523 if(isset($_SESSION[COOKIENAME.'sortRows']))
2524 $queryAdd .= " ORDER BY ".$db->quote_id($_SESSION[COOKIENAME.'sortRows']);
2525 if(isset($_SESSION[COOKIENAME.'orderRows']))
2526 $queryAdd .= " ".$_SESSION[COOKIENAME.'orderRows'];
2527 $queryAdd .= " LIMIT ".$startRow.", ".$numRows;
2528 $query .= $queryAdd;
2529 $queryDisp .= $queryAdd;
2530 $queryTimer = new MicroTimer();
2531 $arr = $db->selectArray($query);
2532 $queryTimer->stop();
2533
2534 //- Show results
2535 if(sizeof($arr)>0)
2536 {
2537 echo "<br/><div class='confirm'>";
2538 echo "<b>".$lang['showing_rows']." ".$startRow." - ".($startRow + sizeof($arr)-1).", ".$lang['total'].": ".$rowCount." ";
2539 printf($lang['query_time'], $queryTimer);
2540 echo "</b><br/>";
2541 echo "<span style='font-size:11px;'>".htmlencode($queryDisp)."</span>";
2542 echo "</div><br/>";
2543
2544 if($target_table_type == 'view')
2545 {
2546 echo sprintf($lang['readonly_tbl'], htmlencode($target_table))." <a href='http://en.wikipedia.org/wiki/View_(database)' target='_blank'>http://en.wikipedia.org/wiki/View_(database)</a>";
2547 echo "<br/><br/>";
2548 }
2549
2550 $query = "PRAGMA table_info(".$db->quote_id($target_table).")";
2551 $result = $db->selectArray($query);
2552 $pkFirstCol = sizeof($result)+1;
2553 //- Table view
2554 if(!isset($_SESSION[COOKIENAME.'viewtype']) || $_SESSION[COOKIENAME.'viewtype']=="table")
2555 {
2556 echo "<form action='?action=row_editordelete&table=".urlencode($target_table)."' method='post' name='checkForm'>";
2557 echo "<table border='0' cellpadding='2' cellspacing='1' class='viewTable'>";
2558 echo "<tr>";
2559 if($target_table_type == 'table')
2560 {
2561 echo "<td colspan='3' class='tdheader' style='text-align:center'>";
2562 echo "<a href='?action=row_view&table=".$target_table."&fulltexts=".($_SESSION[COOKIENAME.'fulltexts']?0:1)."' title='".$lang[($_SESSION[COOKIENAME.'fulltexts']?'no_full_texts':'full_texts')]."'>";
2563 echo "<b>&".($_SESSION[COOKIENAME.'fulltexts']?'r':'l')."arr;</b> T <b>&".($_SESSION[COOKIENAME.'fulltexts']?'l':'r')."arr;</b></a>";
2564 echo "</td>";
2565 }
2566
2567 for($i=0; $i<sizeof($result); $i++)
2568 {
2569 echo "<td class='tdheader'>";
2570 echo "<a href='?action=row_view&table=".urlencode($target_table)."&sort=".urlencode($result[$i]['name']);
2571 if(isset($_SESSION[COOKIENAME.'sortRows']))
2572 $orderTag = ($_SESSION[COOKIENAME.'sortRows']==$result[$i]['name'] && $_SESSION[COOKIENAME.'orderRows']=="ASC") ? "DESC" : "ASC";
2573 else
2574 $orderTag = "ASC";
2575 echo "&order=".$orderTag;
2576 echo "'>".htmlencode($result[$i]['name'])."</a>";
2577 if(isset($_SESSION[COOKIENAME.'sortRows']) && $_SESSION[COOKIENAME.'sortRows']==$result[$i]['name'])
2578 echo (($_SESSION[COOKIENAME.'orderRows']=="ASC") ? " <b>↑</b>" : " <b>↓</b>");
2579 echo "</td>";
2580 }
2581 echo "</tr>";
2582
2583 for($i=0; $i<sizeof($arr); $i++)
2584 {
2585 // -g-> $pk will always be the last columns in each row of the array because we are doing "SELECT *, PK_1, typeof(PK_1), PK2, typeof(PK_2), ... FROM ..."
2586 $pk_arr = array();
2587 for($col = $pkFirstCol; array_key_exists($col, $arr[$i]); $col=$col+2)
2588 {
2589 // in $col we have the type and in $col-1 the value
2590 if($arr[$i][$col]=='integer' || $arr[$i][$col]=='real')
2591 // json encode as int or float, not string
2592 $pk_arr[] = $arr[$i][$col-1]+0;
2593 else
2594 // encode as json string
2595 $pk_arr[] = $arr[$i][$col-1];
2596 }
2597 $pk = json_encode($pk_arr);
2598 $tdWithClass = "<td class='td".($i%2 ? "1" : "2")."'>";
2599 $tdWithClassLeft = "<td class='td".($i%2 ? "1" : "2")."' style='text-align:left;'>";
2600 echo "<tr>";
2601 if($target_table_type == 'table')
2602 {
2603 echo $tdWithClass;
2604 echo "<input type='checkbox' name='check[]' value='".htmlencode($pk)."' id='check_".htmlencode($i)."'/>";
2605 echo "</td>";
2606 echo $tdWithClass;
2607 // -g-> Here, we need to put the PK in as the link for both the edit and delete.
2608 echo "<a href='?table=".urlencode($target_table)."&action=row_editordelete&pk=".urlencode($pk)."&type=edit' title='".$lang['edit']."' class='edit'><span>".$lang['edit']."</span></a>";
2609 echo "</td>";
2610 echo $tdWithClass;
2611 echo "<a href='?table=".urlencode($target_table)."&action=row_editordelete&pk=".urlencode($pk)."&type=delete' title='".$lang['del']."' class='delete'><span>".$lang['del']."</span></a>";
2612 echo "</td>";
2613 }
2614 for($j=0; $j<sizeof($result); $j++)
2615 {
2616 $typeAffinity = get_type_affinity($result[$j]['type']);
2617 if($typeAffinity=="INTEGER" || $typeAffinity=="REAL" || $typeAffinity=="NUMERIC")
2618 echo $tdWithClass;
2619 else
2620 echo $tdWithClassLeft;
2621 if($arr[$i][$j]==="")
2622 echo " ";
2623 elseif($arr[$i][$j]===NULL)
2624 echo "<i class='null'>NULL</i>";
2625 else
2626 echo htmlencode(subString($arr[$i][$j]));
2627 echo "</td>";
2628 }
2629 echo "</tr>";
2630 }
2631 echo "</table>";
2632 if($target_table_type == 'table')
2633 {
2634 echo "<a onclick='checkAll()'>".$lang['chk_all']."</a> / <a onclick='uncheckAll()'>".$lang['unchk_all']."</a> <i>".$lang['with_sel'].":</i> ";
2635 echo "<select name='type'>";
2636 echo "<option value='edit'>".$lang['edit']."</option>";
2637 echo "<option value='delete'>".$lang['del']."</option>";
2638 echo "</select> ";
2639 echo "<input type='submit' value='".$lang['go']."' name='massGo' class='btn'/>";
2640 }
2641 echo "</form>";
2642 }
2643 else
2644 //- Chart view
2645 {
2646 if(!isset($_SESSION[COOKIENAME.$target_table.'chartlabels']))
2647 {
2648 // No label-column set. Try to pick a text-column as label-column.
2649 for($i=0; $i<sizeof($result); $i++)
2650 {
2651 if(get_type_affinity($result[$i]['type'])=='TEXT')
2652 {
2653 $_SESSION[COOKIENAME.$target_table.'chartlabels'] = $i;
2654 break;
2655 }
2656 }
2657 }
2658 if(!isset($_SESSION[COOKIENAME.'chartlabels']))
2659 // no text column found, use the first column
2660 $_SESSION[COOKIENAME.'chartlabels'] = 0;
2661
2662 if(!isset($_SESSION[COOKIENAME.$target_table.'chartvalues']))
2663 {
2664 // No value-column set. Pick the first numeric column if possible.
2665 // If not possible, pick the first column that is not the label-column.
2666
2667 $potential_value_column = null;
2668 for($i=0; $i<sizeof($result); $i++)
2669 {
2670 if($potential_value_column===null && $i != $_SESSION[COOKIENAME.$target_table.'chartlabels'])
2671 // the first column (of any type) that is not the label-column
2672 $potential_value_column = $i;
2673 // check if the col is numeric
2674 $typeAffinity = get_type_affinity($result[$i]['type']);
2675 if($typeAffinity=='INTEGER' || $typeAffinity=='REAL' || $typeAffinity=='NUMERIC')
2676 {
2677 // this is defined as a numeric column, so prefer this as a value column over $potential_value_column
2678 $_SESSION[COOKIENAME.$target_table.'chartvalues'] = $i;
2679 break;
2680 }
2681 }
2682 if(!isset($_SESSION[COOKIENAME.$target_table.'chartvalues']))
2683 {
2684 // we did not find a numeric column
2685 if($potential_value_column!==null)
2686 // use the $potential_value_column, i.e. the second column which is not the label-column
2687 $_SESSION[COOKIENAME.$target_table.'chartvalues'] = $potential_value_column;
2688 else
2689 // it's hopeless, there is only 1 column
2690 $_SESSION[COOKIENAME.$target_table.'chartvalues'] = 0;
2691 }
2692 }
2693
2694 if(!isset($_SESSION[COOKIENAME.'charttype']))
2695 $_SESSION[COOKIENAME.'charttype'] = 'bar';
2696
2697 if(isset($_POST['chartsettings']))
2698 {
2699 $_SESSION[COOKIENAME.'charttype'] = $_POST['charttype'];
2700 $_SESSION[COOKIENAME.$target_table.'chartlabels'] = $_POST['chartlabels'];
2701 $_SESSION[COOKIENAME.$target_table.'chartvalues'] = $_POST['chartvalues'];
2702 }
2703 //- Chart javascript code
2704 ?>
2705 <script type='text/javascript' src='https://www.google.com/jsapi'></script>
2706 <script type='text/javascript'>
2707 google.load('visualization', '1.0', {'packages':['corechart']});
2708 google.setOnLoadCallback(drawChart);
2709 function drawChart()
2710 {
2711 var data = new google.visualization.DataTable();
2712 data.addColumn('string', '<?php echo $result[$_SESSION[COOKIENAME.$target_table.'chartlabels']]['name']; ?>');
2713 data.addColumn('number', '<?php echo $result[$_SESSION[COOKIENAME.$target_table.'chartvalues']]['name']; ?>');
2714 data.addRows([
2715 <?php
2716 for($i=0; $i<sizeof($arr); $i++)
2717 {
2718 $label = str_replace("'", "", htmlencode($arr[$i][$_SESSION[COOKIENAME.$target_table.'chartlabels']]));
2719 $value = htmlencode($arr[$i][$_SESSION[COOKIENAME.$target_table.'chartvalues']]);
2720
2721 if($value==NULL || $value=="")
2722 $value = 0;
2723
2724 echo "['".$label."', ".$value."]";
2725 if($i<sizeof($arr)-1)
2726 echo ",";
2727 }
2728 $height = (sizeof($arr)+1) * 30;
2729 if($height>1000)
2730 $height = 1000;
2731 else if($height<300)
2732 $height = 300;
2733 if($_SESSION[COOKIENAME.'charttype']=="pie")
2734 $height = 800;
2735 ?>
2736 ]);
2737 var chartWidth = document.getElementById("main_column").offsetWidth - document.getElementById("chartsettingsbox").offsetWidth - 100;
2738 if(chartWidth>1000)
2739 chartWidth = 1000;
2740
2741 var options =
2742 {
2743 'width':chartWidth,
2744 'height':<?php echo $height; ?>,
2745 'title':'<?php echo $result[$_SESSION[COOKIENAME.$target_table.'chartlabels']]['name']." vs ".$result[$_SESSION[COOKIENAME.$target_table.'chartvalues']]['name']; ?>'
2746 };
2747 <?php
2748 if($_SESSION[COOKIENAME.'charttype']=="bar")
2749 echo "var chart = new google.visualization.BarChart(document.getElementById('chart_div'));";
2750 else if($_SESSION[COOKIENAME.'charttype']=="pie")
2751 echo "var chart = new google.visualization.PieChart(document.getElementById('chart_div'));";
2752 else
2753 echo "var chart = new google.visualization.LineChart(document.getElementById('chart_div'));";
2754 ?>
2755 chart.draw(data, options);
2756 }
2757 </script>
2758 <div id="chart_div" style="float:left;"><?php echo $lang['no_chart']; ?></div>
2759 <?php
2760 echo "<fieldset style='float:right; text-align:center;' id='chartsettingsbox'><legend><b>Chart Settings</b></legend>";
2761 echo "<form action='?action=row_view&table=".urlencode($target_table)."' method='post'>";
2762 echo $lang['chart_type'].": <select name='charttype'>";
2763 echo "<option value='bar'";
2764 if($_SESSION[COOKIENAME.'charttype']=="bar")
2765 echo " selected='selected'";
2766 echo ">".$lang['chart_bar']."</option>";
2767 echo "<option value='pie'";
2768 if($_SESSION[COOKIENAME.'charttype']=="pie")
2769 echo " selected='selected'";
2770 echo ">".$lang['chart_pie']."</option>";
2771 echo "<option value='line'";
2772 if($_SESSION[COOKIENAME.'charttype']=="line")
2773 echo " selected='selected'";
2774 echo ">".$lang['chart_line']."</option>";
2775 echo "</select>";
2776 echo "<br/><br/>";
2777 echo $lang['lbl'].": <select name='chartlabels'>";
2778 for($i=0; $i<sizeof($result); $i++)
2779 {
2780 if(isset($_SESSION[COOKIENAME.$target_table.'chartlabels']) && $_SESSION[COOKIENAME.$target_table.'chartlabels']==$i)
2781 echo "<option value='".$i."' selected='selected'>".htmlencode($result[$i]['name'])."</option>";
2782 else
2783 echo "<option value='".$i."'>".htmlencode($result[$i]['name'])."</option>";
2784 }
2785 echo "</select>";
2786 echo "<br/><br/>";
2787 echo $lang['val'].": <select name='chartvalues'>";
2788 for($i=0; $i<sizeof($result); $i++)
2789 {
2790 if(isset($_SESSION[COOKIENAME.$target_table.'chartvalues']) && $_SESSION[COOKIENAME.$target_table.'chartvalues']==$i)
2791 echo "<option value='".$i."' selected='selected'>".htmlencode($result[$i]['name'])."</option>";
2792 else
2793 echo "<option value='".$i."'>".htmlencode($result[$i]['name'])."</option>";
2794 }
2795 echo "</select>";
2796 echo "<br/><br/>";
2797 echo "<input type='submit' name='chartsettings' value='".$lang['update']."' class='btn'/>";
2798 echo "</form>";
2799 echo "</fieldset>";
2800 echo "<div style='clear:both;'></div>";
2801 //end chart view
2802 }
2803 }
2804 else if($rowCount>0)//no rows - do nothing
2805 {
2806 echo "<br/><br/>".$lang['no_rows'];
2807 }
2808 elseif($target_table_type == 'table')
2809 {
2810 echo "<br/><br/>".$lang['empty_tbl']." <a href='?table=".urlencode($target_table)."&action=row_create'>".$lang['click']."</a> ".$lang['insert_rows'];
2811 }
2812
2813 break;
2814
2815 //- Create new row (=row_create)
2816 case "row_create":
2817 $fieldStr = "";
2818 echo "<form action='?table=".urlencode($target_table)."&action=row_create' method='post'>";
2819 echo $lang['restart_insert'];
2820 echo " <select name='num'>";
2821 for($i=1; $i<=40; $i++)
2822 {
2823 if(isset($_POST['num']) && $_POST['num']==$i)
2824 echo "<option value='".$i."' selected='selected'>".$i."</option>";
2825 else
2826 echo "<option value='".$i."'>".$i."</option>";
2827 }
2828 echo "</select> ";
2829 echo $lang['rows'];
2830 echo " <input type='submit' value='".$lang['go']."' class='btn'/>";
2831 echo "</form>";
2832 echo "<br/>";
2833 $query = "PRAGMA table_info(".$db->quote_id($target_table).")";
2834 $result = $db->selectArray($query);
2835 echo "<form action='?table=".urlencode($target_table)."&action=row_create&confirm=1' method='post'>";
2836 if(isset($_POST['num']))
2837 $num = $_POST['num'];
2838 else
2839 $num = 1;
2840 echo "<input type='hidden' name='numRows' value='".$num."'/>";
2841 for($j=0; $j<$num; $j++)
2842 {
2843 if($j>0)
2844 echo "<label><input type='checkbox' value='ignore' name='".$j.":ignore' id='row_".$j."_ignore' checked='checked'/> ".$lang['ignore']."</label><br/>";
2845 echo "<table border='0' cellpadding='2' cellspacing='1' class='viewTable'>";
2846 echo "<tr>";
2847 echo "<td class='tdheader'>".$lang['fld']."</td>";
2848 echo "<td class='tdheader'>".$lang['type']."</td>";
2849 echo "<td class='tdheader'>".$lang['func']."</td>";
2850 echo "<td class='tdheader'>Null</td>";
2851 echo "<td class='tdheader'>".$lang['val']."</td>";
2852 echo "</tr>";
2853
2854 for($i=0; $i<sizeof($result); $i++)
2855 {
2856 $field = $result[$i]['name'];
2857 $field_html = htmlencode($field);
2858 if($j==0)
2859 $fieldStr .= ":".$field;
2860 $type = strtolower($result[$i]['type']);
2861 $typeAffinity = get_type_affinity($type);
2862 $tdWithClass = "<td class='td".($i%2 ? "1" : "2")."'>";
2863 $tdWithClassLeft = "<td class='td".($i%2 ? "1" : "2")."' style='text-align:left;'>";
2864 echo "<tr>";
2865 echo $tdWithClassLeft;
2866 echo $field_html;
2867 echo "</td>";
2868 echo $tdWithClassLeft;
2869 echo htmlencode($type);
2870 echo "</td>";
2871 echo $tdWithClassLeft;
2872 echo "<select name='function_".$j."_".$field_html."' onchange='notNull(\"row_".$j."_field_".$i."_null\");'>";
2873 echo "<option value=''> </option>";
2874 foreach (array_merge($sqlite_functions, $custom_functions) as $f) {
2875 echo "<option value='".htmlencode($f)."'>".htmlencode($f)."</option>";
2876 }
2877 echo "</select>";
2878 echo "</td>";
2879 //we need to have a column dedicated to nulls -di
2880 echo $tdWithClassLeft;
2881 if($result[$i]['notnull']==0)
2882 {
2883 if($result[$i]['dflt_value']==="NULL")
2884 echo "<input type='checkbox' name='".$j.":".$field_html."_null' id='row_".$j."_field_".$i."_null' checked='checked' onclick='disableText(this, \"row_".$j."_field_".$i."_value\");'/>";
2885 else
2886 echo "<input type='checkbox' name='".$j.":".$field_html."_null' id='row_".$j."_field_".$i."_null' onclick='disableText(this, \"row_".$j."_field_".$i."_value\");'/>";
2887 }
2888 echo "</td>";
2889 echo $tdWithClassLeft;
2890 if($result[$i]['dflt_value'] === "NULL")
2891 $dflt_value = "";
2892 else
2893 $dflt_value = htmlencode(deQuoteSQL($result[$i]['dflt_value']));
2894
2895 if($typeAffinity=="INTEGER" || $typeAffinity=="REAL" || $typeAffinity=="NUMERIC")
2896 echo "<input type='text' id='row_".$j."_field_".$i."_value' name='".$j.":".$field_html."' value='".$dflt_value."' onblur='changeIgnore(this, \"row_".$j."_ignore\");' onclick='notNull(\"row_".$j."_field_".$i."_null\");'/>";
2897 else
2898 echo "<textarea id='row_".$j."_field_".$i."_value' name='".$j.":".$field_html."' rows='5' cols='60' onclick='notNull(\"row_".$j."_field_".$i."_null\");' onblur='changeIgnore(this, \"row_".$j."_ignore\");'>".$dflt_value."</textarea>";
2899 echo "</td>";
2900 echo "</tr>";
2901 }
2902 echo "<tr>";
2903 echo "<td class='tdheader' style='text-align:right;' colspan='5'>";
2904 echo "<input type='submit' value='".$lang['insert']."' class='btn'/>";
2905 echo "</td>";
2906 echo "</tr>";
2907 echo "</table><br/>";
2908 }
2909 $fieldStr = substr($fieldStr, 1);
2910 echo "<input type='hidden' name='fields' value='".htmlencode($fieldStr)."'/>";
2911 echo "</form>";
2912 break;
2913
2914 //- Edit or delete row (=row_editordelete)
2915 case "row_editordelete":
2916 if(isset($_POST['check']))
2917 $pks = $_POST['check'];
2918 else if(isset($_GET['pk']))
2919 $pks = array($_GET['pk']);
2920 else $pks[0] = "";
2921 $str = $pks[0];
2922 for($i=1; $i<sizeof($pks); $i++)
2923 {
2924 $str .= ", ".$pks[$i];
2925 }
2926 if($str=="") //nothing was selected so show an error
2927 {
2928 echo "<div class='confirm'>";
2929 echo $lang['err'].": ".$lang['no_sel'];
2930 echo "</div>";
2931 echo "<br/><br/><a href='?table=".urlencode($target_table)."&action=row_view'>".$lang['return']."</a>";
2932 }
2933 else
2934 {
2935 if((isset($_POST['type']) && $_POST['type']=="edit") || (isset($_GET['type']) && $_GET['type']=="edit")) //edit
2936 {
2937 echo "<form action='?table=".urlencode($target_table)."&action=row_edit&confirm=1&pk=".urlencode(json_encode($pks))."' method='post'>";
2938 $query = "PRAGMA table_info(".$db->quote_id($target_table).")";
2939 $result = $db->selectArray($query);
2940
2941 //build the POST array of fields
2942 $fieldStr = $result[0][1];
2943 for($j=1; $j<sizeof($result); $j++)
2944 $fieldStr .= ":".$result[$j][1];
2945
2946 $primary_key = $db->getPrimaryKey($target_table);
2947
2948 echo "<input type='hidden' name='fieldArray' value='".htmlencode($fieldStr)."'/>";
2949
2950 for($j=0; $j<sizeof($pks); $j++)
2951 {
2952 $query = "SELECT * FROM ".$db->quote_id($target_table)." WHERE " . $db->wherePK($target_table, json_decode($pks[$j]));
2953 $result1 = $db->select($query);
2954
2955 echo "<table border='0' cellpadding='2' cellspacing='1' class='viewTable'>";
2956 echo "<tr>";
2957 echo "<td class='tdheader'>".$lang['fld']."</td>";
2958 echo "<td class='tdheader'>".$lang['type']."</td>";
2959 echo "<td class='tdheader'>".$lang['func']."</td>";
2960 echo "<td class='tdheader'>Null</td>";
2961 echo "<td class='tdheader'>".$lang['val']."</td>";
2962 echo "</tr>";
2963
2964 for($i=0; $i<sizeof($result); $i++)
2965 {
2966 $field = $result[$i][1];
2967 $type = $result[$i]['type'];
2968 $typeAffinity = get_type_affinity($type);
2969 $value = $result1[$i];
2970 $tdWithClass = "<td class='td".($i%2 ? "1" : "2")."'>";
2971 $tdWithClassLeft = "<td class='td".($i%2 ? "1" : "2")."' style='text-align:left;'>";
2972 echo "<tr>";
2973 echo $tdWithClass;
2974 echo htmlencode($field);
2975 echo "</td>";
2976 echo $tdWithClass;
2977 echo htmlencode($type);
2978 echo "</td>";
2979 echo $tdWithClassLeft;
2980 echo "<select name='function_".htmlencode($field)."[]' onchange='notNull(\"".htmlencode($pks[$j]).":".htmlencode($field)."_null\");'>";
2981 echo "<option value=''></option>";
2982 foreach (array_merge($sqlite_functions, $custom_functions) as $f) {
2983 echo "<option value='".htmlencode($f)."'>".htmlencode($f)."</option>";
2984 }
2985 echo "</select>";
2986 echo "</td>";
2987 echo $tdWithClassLeft;
2988 if($result[$i][3]==0)
2989 {
2990 if($value===NULL)
2991 echo "<input type='checkbox' name='".htmlencode($field)."_null[]' id='".htmlencode($pks[$j]).":".htmlencode($field)."_null' checked='checked'/>";
2992 else
2993 echo "<input type='checkbox' name='".htmlencode($field)."_null[]' id='".htmlencode($pks[$j]).":".htmlencode($field)."_null'/>";
2994 }
2995 echo "</td>";
2996 echo $tdWithClassLeft;
2997 if($typeAffinity=="INTEGER" || $typeAffinity=="REAL" || $typeAffinity=="NUMERIC")
2998 echo "<input type='text' name='".htmlencode($field)."[]' value='".htmlencode($value)."' onblur='changeIgnore(this, \"".$j."\", \"".htmlencode($pks[$j]).":".htmlencode($field)."_null\")' />";
2999 else
3000 echo "<textarea name='".htmlencode($field)."[]' rows='1' cols='60' class='".htmlencode($field)."_textarea' onblur='changeIgnore(this, \"".$j."\", \"".htmlencode($pks[$j]).":".htmlencode($field)."_null\")'>".htmlencode($value)."</textarea>";
3001 echo "</td>";
3002 echo "</tr>";
3003 }
3004 echo "<tr>";
3005 echo "<td class='tdheader' style='text-align:right;' colspan='5'>";
3006 // Note: the 'Save changes' button must be first in the code so it is the one used when submitting the form with the Enter key (issue #215)
3007 echo "<input type='submit' value='".$lang['save_ch']."' class='btn'/> ";
3008 echo "<input type='submit' name='new_row' value='".$lang['new_insert']."' class='btn'/> ";
3009 echo "<a href='?table=".urlencode($target_table)."&action=row_view'>".$lang['cancel']."</a>";
3010 echo "</td>";
3011 echo "</tr>";
3012 echo "</table>";
3013 echo "<br/>";
3014 }
3015 echo "</form>";
3016 }
3017 else //delete
3018 {
3019 echo "<form action='?table=".urlencode($target_table)."&action=row_delete&confirm=1&pk=".urlencode(json_encode($pks))."' method='post'>";
3020 echo "<div class='confirm'>";
3021 printf($lang['ques_del_rows'], htmlencode($str), htmlencode($target_table));
3022 echo "<br/><br/>";
3023 echo "<input type='submit' value='".$lang['confirm']."' class='btn'/> ";
3024 echo "<a href='?table=".urlencode($target_table)."&action=row_view'>".$lang['cancel']."</a>";
3025 echo "</div>";
3026 }
3027 }
3028 break;
3029
3030 //- Column actions
3031
3032 //- View table structure (=column_view)
3033 case "column_view":
3034 $query = "PRAGMA table_info(".$db->quote_id($target_table).")";
3035 $result = $db->selectArray($query);
3036
3037 echo "<form action='?table=".urlencode($target_table)."&action=column_confirm' method='post' name='checkForm'>";
3038 echo "<table border='0' cellpadding='2' cellspacing='1' class='viewTable'>";
3039 echo "<tr>";
3040 if($target_table_type == 'table')
3041 echo "<td colspan='3'></td>";
3042 echo "<td class='tdheader'>".$lang['col']." #</td>";
3043 echo "<td class='tdheader'>".$lang['fld']."</td>";
3044 echo "<td class='tdheader'>".$lang['type']."</td>";
3045 echo "<td class='tdheader'>".$lang['not_null']."</td>";
3046 echo "<td class='tdheader'>".$lang['def_val']."</td>";
3047 echo "<td class='tdheader'>".$lang['prim_key']."</td>";
3048 echo "</tr>";
3049
3050 $noPrimaryKey = true;
3051
3052 for($i=0; $i<sizeof($result); $i++)
3053 {
3054 $colVal = $result[$i][0];
3055 $fieldVal = $result[$i][1];
3056 $typeVal = $result[$i]['type'];
3057 $notnullVal = $result[$i][3];
3058 $defaultVal = $result[$i][4];
3059 $primarykeyVal = $result[$i][5];
3060
3061 if(intval($notnullVal)!=0)
3062 $notnullVal = $lang['yes'];
3063 else
3064 $notnullVal = $lang['no'];
3065 if(intval($primarykeyVal)!=0)
3066 {
3067 $primarykeyVal = $lang['yes'];
3068 $noPrimaryKey = false;
3069 }
3070 else
3071 $primarykeyVal = $lang['no'];
3072
3073 $tdWithClass = "<td class='td".($i%2 ? "1" : "2")."'>";
3074 $tdWithClassLeft = "<td class='td".($i%2 ? "1" : "2")."' style='text-align:left;'>";
3075 echo "<tr>";
3076 if($target_table_type == 'table')
3077 {
3078 echo $tdWithClass;
3079 echo "<input type='checkbox' name='check[]' value='".htmlencode($fieldVal)."' id='check_".$i."'/>";
3080 echo "</td>";
3081 echo $tdWithClass;
3082 echo "<a href='?table=".urlencode($target_table)."&action=column_edit&pk=".urlencode($fieldVal)."' title='".$lang['edit']."' class='edit'><span>".$lang['edit']."</span></a>";
3083 echo "</td>";
3084 echo $tdWithClass;
3085 echo "<a href='?table=".urlencode($target_table)."&action=column_confirm&action2=column_delete&pk=".urlencode($fieldVal)."' title='".$lang['del']."' class='delete'><span>".$lang['del']."</span></a>";
3086 echo "</td>";
3087 }
3088 echo $tdWithClass;
3089 echo htmlencode($colVal);
3090 echo "</td>";
3091 echo $tdWithClassLeft;
3092 echo htmlencode($fieldVal);
3093 echo "</td>";
3094 echo $tdWithClassLeft;
3095 echo htmlencode($typeVal);
3096 echo "</td>";
3097 echo $tdWithClassLeft;
3098 echo htmlencode($notnullVal);
3099 echo "</td>";
3100 echo $tdWithClassLeft;
3101 if($defaultVal===NULL)
3102 echo "<i class='null'>".$lang['none']."</i>";
3103 elseif($defaultVal==="NULL")
3104 echo "<i class='null'>NULL</i>";
3105 else
3106 echo htmlencode($defaultVal);
3107 echo "</td>";
3108 echo $tdWithClassLeft;
3109 echo htmlencode($primarykeyVal);
3110 echo "</td>";
3111 echo "</tr>";
3112 }
3113
3114 echo "</table>";
3115 if($target_table_type == 'table')
3116 {
3117 echo "<a onclick='checkAll()'>".$lang['chk_all']."</a> / <a onclick='uncheckAll()'>".$lang['unchk_all']."</a> <i>".$lang['with_sel'].":</i> ";
3118 echo "<select name='action2'>";
3119 //echo "<option value='edit'>".$lang['edit']."</option>";
3120 echo "<option value='column_delete'>".$lang['del']."</option>";
3121 if($noPrimaryKey)
3122 echo "<option value='primarykey_add'>".$lang['prim_key']."</option>";
3123 echo "</select> ";
3124 echo "<input type='submit' value='".$lang['go']."' name='massGo' class='btn'/>";
3125 }
3126 echo "</form>";
3127 if($target_table_type == 'table')
3128 {
3129 echo "<br/>";
3130 echo "<form action='?table=".urlencode($target_table)."&action=column_create' method='post'>";
3131 echo "<input type='hidden' name='tablename' value='".htmlencode($target_table)."'/>";
3132 echo $lang['add']." <input type='text' name='tablefields' style='width:30px;' value='1'/> ".$lang['tbl_end']." <input type='submit' value='".$lang['go']."' name='addfields' class='btn'/>";
3133 echo "</form>";
3134 }
3135
3136 $query = "SELECT sql FROM sqlite_master WHERE name=".$db->quote($target_table);
3137 $master = $db->selectArray($query);
3138
3139 echo "<br/>";
3140 echo "<br/>";
3141 echo "<div class='confirm'>";
3142 echo "<b>".$lang['query_used_'.$target_table_type]."</b><br/>";
3143 echo "<span style='font-size:11px;'>".htmlencode($master[0]['sql'])."</span>";
3144 echo "</div>";
3145 echo "<br/>";
3146 if($target_table_type == 'view')
3147 {
3148 echo "<br/><hr/><br/>";
3149 //$query = "SELECT * FROM sqlite_master WHERE type='index' AND tbl_name='".$target_table."'";
3150 $query = "PRAGMA index_list(".$db->quote_id($target_table).")";
3151 $result = $db->selectArray($query);
3152 if(sizeof($result)>0)
3153 {
3154 echo "<h2>".$lang['indexes'].":</h2>";
3155 echo "<table border='0' cellpadding='2' cellspacing='1' class='viewTable'>";
3156 echo "<tr>";
3157 echo "<td colspan='1'>";
3158 echo "</td>";
3159 echo "<td class='tdheader'>".$lang['name']."</td>";
3160 echo "<td class='tdheader'>".$lang['unique']."</td>";
3161 echo "<td class='tdheader'>".$lang['seq_no']."</td>";
3162 echo "<td class='tdheader'>".$lang['col']." #</td>";
3163 echo "<td class='tdheader'>".$lang['fld']."</td>";
3164 echo "</tr>";
3165 for($i=0; $i<sizeof($result); $i++)
3166 {
3167 if($result[$i]['unique']==0)
3168 $unique = $lang['no'];
3169 else
3170 $unique = $lang['yes'];
3171
3172 $query = "PRAGMA index_info(".$db->quote_id($result[$i]['name']).")";
3173 $info = $db->selectArray($query);
3174 $span = sizeof($info);
3175
3176 $tdWithClass = "<td class='td".($i%2 ? "1" : "2")."'>";
3177 $tdWithClassLeft = "<td class='td".($i%2 ? "1" : "2")."' style='text-align:left;'>";
3178 $tdWithClassSpan = "<td class='td".($i%2 ? "1" : "2")."' rowspan='".$span."'>";
3179 $tdWithClassLeftSpan = "<td class='td".($i%2 ? "1" : "2")."' style='text-align:left;' rowspan='".$span."'>";
3180 echo "<tr>";
3181 echo $tdWithClassSpan;
3182 echo "<a href='?table=".urlencode($target_table)."&action=index_delete&pk=".urlencode($result[$i]['name'])."' title='".$lang['del']."' class='delete'><span>".$lang['del']."</span></a>";
3183 echo "</td>";
3184 echo $tdWithClassLeftSpan;
3185 echo $result[$i]['name'];
3186 echo "</td>";
3187 echo $tdWithClassLeftSpan;
3188 echo $unique;
3189 echo "</td>";
3190 for($j=0; $j<$span; $j++)
3191 {
3192 if($j!=0)
3193 echo "<tr>";
3194 echo $tdWithClassLeft;
3195 echo htmlencode($info[$j]['seqno']);
3196 echo "</td>";
3197 echo $tdWithClassLeft;
3198 echo htmlencode($info[$j]['cid']);
3199 echo "</td>";
3200 echo $tdWithClassLeft;
3201 echo htmlencode($info[$j]['name']);
3202 echo "</td>";
3203 echo "</tr>";
3204 }
3205 }
3206 echo "</table><br/><br/>";
3207 }
3208
3209 $query = "SELECT * FROM sqlite_master WHERE type='trigger' AND tbl_name=".$db->quote($target_table)." ORDER BY name";
3210 $result = $db->selectArray($query);
3211 //print_r($result);
3212 if(sizeof($result)>0)
3213 {
3214 echo "<h2>".$lang['triggers'].":</h2>";
3215 echo "<table border='0' cellpadding='2' cellspacing='1' class='viewTable'>";
3216 echo "<tr>";
3217 echo "<td colspan='1'>";
3218 echo "</td>";
3219 echo "<td class='tdheader'>".$lang['name']."</td>";
3220 echo "<td class='tdheader'>".$lang['sql']."</td>";
3221 echo "</tr>";
3222 for($i=0; $i<sizeof($result); $i++)
3223 {
3224 $tdWithClass = "<td class='td".($i%2 ? "1" : "2")."'>";
3225 echo "<tr>";
3226 echo $tdWithClass;
3227 echo "<a href='?table=".urlencode($target_table)."&action=trigger_delete&pk=".urlencode($result[$i]['name'])."' title='".$lang['del']."' class='delete'><span>".$lang['del']."</span></a>";
3228 echo "</td>";
3229 echo $tdWithClass;
3230 echo htmlencode($result[$i]['name']);
3231 echo "</td>";
3232 echo $tdWithClass;
3233 echo htmlencode($result[$i]['sql']);
3234 echo "</td>";
3235 }
3236 echo "</table><br/><br/>";
3237 }
3238
3239 echo "<form action='?table=".urlencode($target_table)."&action=index_create' method='post'>";
3240 echo "<input type='hidden' name='tablename' value='".htmlencode($target_table)."'/>";
3241 echo "<br/><div class='tdheader'>";
3242 echo $lang['create_index2']." <input type='text' name='numcolumns' style='width:30px;' value='1'/> ".$lang['cols']." <input type='submit' value='".$lang['go']."' name='addindex' class='btn'/>";
3243 echo "</div>";
3244 echo "</form>";
3245
3246 echo "<form action='?table=".urlencode($target_table)."&action=trigger_create' method='post'>";
3247 echo "<input type='hidden' name='tablename' value='".htmlencode($target_table)."'/>";
3248 echo "<br/><div class='tdheader'>";
3249 echo $lang['create_trigger2']." <input type='submit' value='".$lang['go']."' name='addindex' class='btn'/>";
3250 echo "</div>";
3251 echo "</form>";
3252 }
3253 break;
3254
3255 //- Create column (=column_create)
3256 case "column_create":
3257 echo "<h2>".sprintf($lang['new_fld'],htmlencode($_POST['tablename']))."</h2>";
3258 if($_POST['tablefields']=="" || intval($_POST['tablefields'])<=0)
3259 echo $lang['specify_fields'];
3260 else if($_POST['tablename']=="")
3261 echo $lang['specify_tbl'];
3262 else
3263 {
3264 $num = intval($_POST['tablefields']);
3265 $name = $_POST['tablename'];
3266 echo "<form action='?table=".urlencode($_POST['tablename'])."&action=column_create&confirm=1' method='post'>";
3267 echo "<input type='hidden' name='tablename' value='".htmlencode($name)."'/>";
3268 echo "<input type='hidden' name='rows' value='".$num."'/>";
3269 echo "<table border='0' cellpadding='2' cellspacing='1' class='viewTable'>";
3270 echo "<tr>";
3271 $headings = array($lang["fld"], $lang["type"], $lang["prim_key"]);
3272 if($db->getType() != "SQLiteDatabase") $headings[] = $lang["autoincrement"];
3273 $headings[] = $lang["not_null"];
3274 $headings[] = $lang["def_val"];
3275
3276 for($k=0; $k<count($headings); $k++)
3277 echo "<td class='tdheader'>" . $headings[$k] . "</td>";
3278 echo "</tr>";
3279
3280 for($i=0; $i<$num; $i++)
3281 {
3282 $tdWithClass = "<td class='td" . ($i%2 ? "1" : "2") . "'>";
3283 echo "<tr>";
3284 echo $tdWithClass;
3285 echo "<input type='text' name='".$i."_field' style='width:200px;'/>";
3286 echo "</td>";
3287 echo $tdWithClass;
3288 echo "<select name='".$i."_type' id='i".$i."_type' onchange='toggleAutoincrement(".$i.");'>";
3289 foreach ($sqlite_datatypes as $t) {
3290 echo "<option value='".htmlencode($t)."'>".htmlencode($t)."</option>";
3291 }
3292 echo "</select>";
3293 echo "</td>";
3294 echo $tdWithClass;
3295 echo "<label><input type='checkbox' name='".$i."_primarykey'/> ".$lang['yes']."</label>";
3296 echo "</td>";
3297 if($db->getType() != "SQLiteDatabase")
3298 {
3299 echo $tdWithClass;
3300 echo "<label><input type='checkbox' name='".$i."_autoincrement' id='i".$i."_autoincrement'/> ".$lang['yes']."</label>";
3301 echo "</td>";
3302 }
3303 echo $tdWithClass;
3304 echo "<label><input type='checkbox' name='".$i."_notnull'/> ".$lang['yes']."</label>";
3305 echo "</td>";
3306 echo $tdWithClass;
3307 echo "<select name='".$i."_defaultoption' id='i".$i."_defaultoption' onchange=\"if(this.value!='defined' && this.value!='expr') document.getElementById('i".$i."_defaultvalue').value='';\">";
3308 echo "<option value='none'>".$lang['none']."</option><option value='defined'>".$lang['as_defined'].":</option><option>NULL</option><option>CURRENT_TIME</option><option>CURRENT_DATE</option><option>CURRENT_TIMESTAMP</option><option value='expr'>".$lang['expression'].":</option>";
3309 echo "</select>";
3310 echo "<input type='text' name='".$i."_defaultvalue' id='i".$i."_defaultvalue' style='width:100px;' onchange=\"if(document.getElementById('i".$i."_defaultoption').value!='expr') document.getElementById('i".$i."_defaultoption').value='defined';\"/>";
3311 echo "</td>";
3312 echo "</tr>";
3313 }
3314 echo "<tr>";
3315 echo "<td class='tdheader' style='text-align:right;' colspan='6'>";
3316 echo "<input type='submit' value='".$lang['add_flds']."' class='btn'/> ";
3317 echo "<a href='?table=".urlencode($_POST['tablename'])."&action=column_view'>".$lang['cancel']."</a>";
3318 echo "</td>";
3319 echo "</tr>";
3320 echo "</table>";
3321 echo "</form>";
3322 }
3323 break;
3324
3325 //- Delete column (=column_confirm)
3326 case "column_confirm":
3327 if(isset($_POST['check']))
3328 $pks = $_POST['check'];
3329 elseif(isset($_GET['pk']))
3330 $pks = array($_GET['pk']);
3331 else $pks = array();
3332
3333 if(sizeof($pks)==0) //nothing was selected so show an error
3334 {
3335 echo "<div class='confirm'>";
3336 echo $lang['err'].": ".$lang['no_sel'];
3337 echo "</div>";
3338 echo "<br/><br/><a href='?table=".urlencode($target_table)."&action=column_view'>".$lang['return']."</a>";
3339 }
3340 else
3341 {
3342 $str = $pks[0];
3343 $pkVal = $pks[0];
3344 for($i=1; $i<sizeof($pks); $i++)
3345 {
3346 $str .= ", ".$pks[$i];
3347 $pkVal .= ":".$pks[$i];
3348 }
3349 echo "<form action='?table=".urlencode($target_table)."&action=".$_REQUEST['action2']."&confirm=1&pk=".urlencode($pkVal)."' method='post'>";
3350 echo "<div class='confirm'>";
3351 printf($lang['ques_'.$_REQUEST['action2']], htmlencode($str), htmlencode($target_table));
3352 echo "<br/><br/>";
3353 echo "<input type='submit' value='".$lang['confirm']."' class='btn'/> ";
3354 echo "<a href='?table=".urlencode($target_table)."&action=column_view'>".$lang['cancel']."</a>";
3355 echo "</div>";
3356 }
3357 break;
3358
3359 //- Edit column (=column_edit)
3360 case "column_edit":
3361 echo "<h2>".sprintf($lang['edit_col'], htmlencode($_GET['pk']))." ".$lang['on_tbl']." '".htmlencode($target_table)."'</h2>";
3362 echo $lang['sqlite_limit']."<br/><br/>";
3363 if(!isset($_GET['pk']))
3364 echo $lang['specify_col'];
3365 else if (!$target_table)
3366 echo $lang['specify_tbl'];
3367 else
3368 {
3369 $query = "PRAGMA table_info(".$db->quote_id($target_table).")";
3370 $result = $db->selectArray($query);
3371
3372 for($i=0; $i<sizeof($result); $i++)
3373 {
3374 if($result[$i][1]==$_GET['pk'])
3375 {
3376 $colVal = $result[$i][0];
3377 $fieldVal = $result[$i][1];
3378 $typeVal = $result[$i]['type'];
3379 $notnullVal = $result[$i][3];
3380 $defaultVal = $result[$i][4];
3381 $primarykeyVal = $result[$i][5];
3382 break;
3383 }
3384 }
3385
3386 $name = $target_table;
3387 echo "<form action='?table=".urlencode($name)."&action=column_edit&confirm=1' method='post'>";
3388 echo "<input type='hidden' name='tablename' value='".htmlencode($name)."'/>";
3389 echo "<input type='hidden' name='oldvalue' value='".htmlencode($_GET['pk'])."'/>";
3390 echo "<table border='0' cellpadding='2' cellspacing='1' class='viewTable'>";
3391 echo "<tr>";
3392 //$headings = array("Field", "Type", "Primary Key", "Autoincrement", "Not NULL", "Default Value");
3393 $headings = array($lang["fld"], $lang["type"]);
3394 for($k=0; $k<count($headings); $k++)
3395 echo "<td class='tdheader'>".$headings[$k]."</td>";
3396 echo "</tr>";
3397
3398 $i = 0;
3399 $tdWithClass = "<td class='td" . ($i%2 ? "1" : "2") . "'>";
3400 echo "<tr>";
3401 echo $tdWithClass;
3402 echo "<input type='text' name='".$i."_field' style='width:200px;' value='".htmlencode($fieldVal)."'/>";
3403 echo "</td>";
3404 echo $tdWithClass;
3405 echo "<select name='".$i."_type' id='i".$i."_type' onchange='toggleAutoincrement(".$i.");'>";
3406 if(!in_array($typeVal, $sqlite_datatypes))
3407 echo "<option value='".htmlencode($typeVal)."' selected='selected'>".htmlencode($typeVal)."</option>";
3408 foreach ($sqlite_datatypes as $t) {
3409 if($t==$typeVal)
3410 echo "<option value='".htmlencode($t)."' selected='selected'>".htmlencode($t)."</option>";
3411 else
3412 echo "<option value='".htmlencode($t)."'>".htmlencode($t)."</option>";
3413 }
3414 echo "</select>";
3415 echo "</td>";
3416 /*
3417 echo $tdWithClass;
3418 if($primarykeyVal)
3419 echo "<input type='checkbox' name='".$i."_primarykey' checked='checked'/> Yes";
3420 else
3421 echo "<input type='checkbox' name='".$i."_primarykey'/> Yes";
3422 echo "</td>";
3423 echo $tdWithClass;
3424 if(1==2)
3425 echo "<input type='checkbox' name='".$i."_autoincrement' id='".$i."_autoincrement' checked='checked'/> Yes";
3426 else
3427 echo "<input type='checkbox' name='".$i."_autoincrement' id='".$i."_autoincrement'/> Yes";
3428 echo "</td>";
3429 echo $tdWithClass;
3430 if($notnullVal)
3431 echo "<input type='checkbox' name='".$i."_notnull' checked='checked'/> Yes";
3432 else
3433 echo "<input type='checkbox' name='".$i."_notnull'/> Yes";
3434 echo "</td>";
3435 echo $tdWithClass;
3436 echo "<input type='text' name='".$i."_defaultvalue' value='".$defaultVal."' style='width:100px;'/>";
3437 echo "</td>";
3438 */
3439 echo "</tr>";
3440
3441 echo "<tr>";
3442 echo "<td class='tdheader' style='text-align:right;' colspan='6'>";
3443 echo "<input type='submit' value='".$lang['save_ch']."' class='btn'/> ";
3444 echo "<a href='?table=".urlencode($target_table)."&action=column_view'>".$lang['cancel']."</a>";
3445 echo "</td>";
3446 echo "</tr>";
3447 echo "</table>";
3448 echo "</form>";
3449 }
3450 break;
3451
3452 //- Delete index (=index_delete)
3453 case "index_delete":
3454 echo "<form action='?table=".urlencode($target_table)."&action=index_delete&pk=".urlencode($_GET['pk'])."&confirm=1' method='post'>";
3455 echo "<div class='confirm'>";
3456 echo sprintf($lang['ques_del_index'], htmlencode($_GET['pk']))."<br/><br/>";
3457 echo "<input type='submit' value='".$lang['confirm']."' class='btn'/> ";
3458 echo "<a href='?table=".urlencode($target_table)."&action=column_view'>".$lang['cancel']."</a>";
3459 echo "</div>";
3460 echo "</form>";
3461 break;
3462
3463 //- Delete trigger (=trigger_delete)
3464 case "trigger_delete":
3465 echo "<form action='?table=".urlencode($target_table)."&action=trigger_delete&pk=".urlencode($_GET['pk'])."&confirm=1' method='post'>";
3466 echo "<div class='confirm'>";
3467 echo sprintf($lang['ques_del_trigger'], htmlencode($_GET['pk']))."<br/><br/>";
3468 echo "<input type='submit' value='".$lang['confirm']."' class='btn'/> ";
3469 echo "<a href='?table=".urlencode($target_table)."&action=column_view'>".$lang['cancel']."</a>";
3470 echo "</div>";
3471 echo "</form>";
3472 break;
3473
3474 //- Create trigger (=trigger_create)
3475 case "trigger_create":
3476 echo "<h2>".$lang['create_trigger']." '".htmlencode($_POST['tablename'])."'</h2>";
3477 if($_POST['tablename']=="")
3478 echo $lang['specify_tbl'];
3479 else
3480 {
3481 echo "<form action='?table=".urlencode($_POST['tablename'])."&action=trigger_create&confirm=1' method='post'>";
3482 echo $lang['trigger_name'].": <input type='text' name='trigger_name'/><br/><br/>";
3483 echo "<fieldset><legend>".$lang['db_event']."</legend>";
3484 echo $lang['before']."/".$lang['after'].": ";
3485 echo "<select name='beforeafter'>";
3486 echo "<option value=''></option>";
3487 echo "<option value='BEFORE'>".$lang['before']."</option>";
3488 echo "<option value='AFTER'>".$lang['after']."</option>";
3489 echo "<option value='INSTEAD OF'>".$lang['instead']."</option>";
3490 echo "</select>";
3491 echo "<br/><br/>";
3492 echo $lang['event'].": ";
3493 echo "<select name='event'>";
3494 echo "<option value='DELETE'>".$lang['del']."</option>";
3495 echo "<option value='INSERT'>".$lang['insert']."</option>";
3496 echo "<option value='UPDATE'>".$lang['update']."</option>";
3497 echo "</select>";
3498 echo "</fieldset><br/><br/>";
3499 echo "<fieldset><legend>".$lang['trigger_act']."</legend>";
3500 echo "<label><input type='checkbox' name='foreachrow'/> ".$lang['each_row']."</label><br/><br/>";
3501 echo $lang['when_exp'].":<br/>";
3502 echo "<textarea name='whenexpression' style='width:500px; height:100px;' rows='8' cols='50'></textarea>";
3503 echo "<br/><br/>";
3504 echo $lang['trigger_step'].":<br/>";
3505 echo "<textarea name='triggersteps' style='width:500px; height:100px;' rows='8' cols='50'></textarea>";
3506 echo "</fieldset><br/><br/>";
3507 echo "<input type='submit' value='".$lang['create_trigger2']."' class='btn'/> ";
3508 echo "<a href='?table=".urlencode($_POST['tablename'])."&action=column_view'>".$lang['cancel']."</a>";
3509 echo "</form>";
3510 }
3511 break;
3512
3513 //- Create index (=index_create)
3514 case "index_create":
3515 echo "<h2>".$lang['create_index']." '".htmlencode($_POST['tablename'])."'</h2>";
3516 if($_POST['numcolumns']=="" || intval($_POST['numcolumns'])<=0)
3517 echo $lang['specify_fields'];
3518 else if($_POST['tablename']=="")
3519 echo $lang['specify_tbl'];
3520 else
3521 {
3522 echo "<form action='?table=".urlencode($_POST['tablename'])."&action=index_create&confirm=1' method='post'>";
3523 $num = intval($_POST['numcolumns']);
3524 $query = "PRAGMA table_info(".$db->quote_id($_POST['tablename']).")";
3525
3526 $result = $db->selectArray($query);
3527 echo "<fieldset><legend>".$lang['define_index']."</legend>";
3528 echo $lang['index_name'].": <input type='text' name='name'/><br/>";
3529 echo $lang['dup_val'].": ";
3530 echo "<select name='duplicate'>";
3531 echo "<option value='yes'>".$lang['allow']."</option>";
3532 echo "<option value='no'>".$lang['not_allow']."</option>";
3533 echo "</select><br/>";
3534 echo "</fieldset>";
3535 echo "<br/>";
3536 echo "<fieldset><legend>".$lang['define_in_col']."</legend>";
3537 for($i=0; $i<$num; $i++)
3538 {
3539 echo "<select name='".$i."_field'>";
3540 echo "<option value=''>--".$lang['ignore']."--</option>";
3541 for($j=0; $j<sizeof($result); $j++)
3542 echo "<option value='".htmlencode($result[$j][1])."'>".htmlencode($result[$j][1])."</option>";
3543 echo "</select> ";
3544 echo "<select name='".$i."_order'>";
3545 echo "<option value=''></option>";
3546 echo "<option value=' ASC'>".$lang['asc']."</option>";
3547 echo "<option value=' DESC'>".$lang['desc']."</option>";
3548 echo "</select><br/>";
3549 }
3550 echo "</fieldset>";
3551 echo "<br/><br/>";
3552 echo "<input type='hidden' name='num' value='".$num."'/>";
3553 echo "<input type='submit' value='".$lang['create_index1']."' class='btn'/> ";
3554 echo "<a href='?table=".urlencode($_POST['tablename'])."&action=column_view'>".$lang['cancel']."</a>";
3555 echo "</form>";
3556 }
3557 break;
3558 }
3559 echo "</div>";
3560}
3561
3562$view = "structure";
3563
3564//- HMTL: tabs for databases
3565if(!$target_table && !isset($_GET['confirm']) && (!isset($_GET['action']) || (isset($_GET['action']) && $_GET['action']!="table_create"))) //the absence of these fields means we are viewing the database homepage
3566{
3567 $view = isset($_GET['view']) ? $_GET['view'] : 'structure';
3568
3569 echo "<a href='?view=structure' ";
3570 if($view=="structure")
3571 echo "class='tab_pressed'";
3572 else
3573 echo "class='tab'";
3574 echo ">".$lang['struct']."</a>";
3575 echo "<a href='?view=sql' ";
3576 if($view=="sql")
3577 echo "class='tab_pressed'";
3578 else
3579 echo "class='tab'";
3580 echo ">".$lang['sql']."</a>";
3581 echo "<a href='?view=export' ";
3582 if($view=="export")
3583 echo "class='tab_pressed'";
3584 else
3585 echo "class='tab'";
3586 echo ">".$lang['export']."</a>";
3587 echo "<a href='?view=import' ";
3588 if($view=="import")
3589 echo "class='tab_pressed'";
3590 else
3591 echo "class='tab'";
3592 echo ">".$lang['import']."</a>";
3593 echo "<a href='?view=vacuum' ";
3594 if($view=="vacuum")
3595 echo "class='tab_pressed'";
3596 else
3597 echo "class='tab'";
3598 echo ">".$lang['vac']."</a>";
3599 if($directory!==false && is_writable($directory))
3600 {
3601 echo "<a href='?view=rename' ";
3602 if($view=="rename")
3603 echo "class='tab_pressed'";
3604 else
3605 echo "class='tab'";
3606 echo ">".$lang['db_rename']."</a>";
3607
3608 echo "<a href='?view=delete' title='".$lang['db_del']."' ";
3609 if($view=="delete")
3610 echo "class='tab_pressed delete_db'";
3611 else
3612 echo "class='tab delete_db'";
3613 echo "><span>".$lang['db_del']."</span></a>";
3614 }
3615 echo "<div style='clear:both;'></div>";
3616 echo "<div id='main'>";
3617
3618 //- Switch on $view (actually a series of if-else)
3619
3620 if($view=="structure")
3621 {
3622 //- Database structure, shows all the tables (=structure)
3623 $query = "SELECT sqlite_version() AS sqlite_version";
3624 $queryVersion = $db->select($query);
3625 $realVersion = $queryVersion['sqlite_version'];
3626
3627 if(isset($dbexists))
3628 {
3629 echo "<div class='confirm' style='margin:10px 20px;'>";
3630 echo $lang['err'].': '.sprintf($lang['db_exists'], htmlencode($dbname));
3631 echo "</div><br/>";
3632 }
3633
3634 if($db->isWritable() && !$db->isDirWritable())
3635 {
3636 echo "<div class='confirm' style='margin:10px 20px;'>";
3637 echo $lang['attention'].': '.$lang['directory_not_writable'];
3638 echo "</div><br/>";
3639 }
3640
3641 if(isset($extension_not_allowed))
3642 {
3643 echo "<div class='confirm' style='margin:10px 20px;'>";
3644 echo $lang['extension_not_allowed'].': ';
3645 echo implode(', ', array_map('htmlencode', $allowed_extensions));
3646 echo '<br />'.$lang['add_allowed_extension'];
3647 echo "</div><br/>";
3648 }
3649
3650 if ($auth->isPasswordDefault())
3651 {
3652 echo "<div class='confirm' style='margin:20px 0px;'>";
3653 echo sprintf($lang['warn_passwd'],(is_readable('phpliteadmin.config.php')?'phpliteadmin.config.php':PAGE))."<br />".$lang['warn0'];
3654 echo "</div>";
3655 }
3656
3657 echo "<b>".$lang['db_name']."</b>: ".htmlencode($db->getName())."<br/>";
3658 echo "<b>".$lang['db_path']."</b>: ".htmlencode($db->getPath())."<br/>";
3659 echo "<b>".$lang['db_size']."</b>: ".$db->getSize()." KB<br/>";
3660 echo "<b>".$lang['db_mod']."</b>: ".$db->getDate()."<br/>";
3661 echo "<b>".$lang['sqlite_v']."</b>: ".$realVersion."<br/>";
3662 echo "<b>".$lang['sqlite_ext']."</b> ".helpLink($lang['help1']).": ".$db->getType()."<br/>";
3663 echo "<b>".$lang['php_v']."</b>: ".phpversion()."<br/>";
3664 echo "<b>".PROJECT." ".$lang["ver"]."</b>: ".VERSION;
3665 echo " <a href='".PROJECT_URL."' target='_blank' id='oldVersion' style='display: none;' class='warning'>".$lang['new_version']."</a><br/><br/>";
3666 echo "<script type='text/javascript'>checkVersion('".VERSION."','".VERSION_CHECK_URL."');</script>";
3667
3668 if(isset($_GET['sort']) && ($_GET['sort']=='type' || $_GET['sort']=='name'))
3669 $_SESSION[COOKIENAME.'sortTables'] = $_GET['sort'];
3670 if(isset($_GET['order']) && ($_GET['order']=='ASC' || $_GET['order']=='DESC'))
3671 $_SESSION[COOKIENAME.'orderTables'] = $_GET['order'];
3672
3673 $query = "SELECT type, name FROM sqlite_master WHERE (type='table' OR type='view') AND name!='' AND name NOT LIKE 'sqlite_%'";
3674 $queryAdd = "";
3675 if(isset($_SESSION[COOKIENAME.'sortTables']))
3676 $queryAdd .= " ORDER BY ".$db->quote_id($_SESSION[COOKIENAME.'sortTables']);
3677 else
3678 $queryAdd .= " ORDER BY \"name\"";
3679 if(isset($_SESSION[COOKIENAME.'orderTables']))
3680 $queryAdd .= " ".$_SESSION[COOKIENAME.'orderTables'];
3681 $query .= $queryAdd;
3682 $result = $db->selectArray($query);
3683
3684 if(sizeof($result)==0)
3685 echo $lang['no_tbl']."<br/><br/>";
3686 else
3687 {
3688 echo "<table border='0' cellpadding='2' cellspacing='1' class='viewTable'>";
3689 echo "<tr>";
3690
3691 echo "<td class='tdheader'>";
3692 echo "<a href='?sort=type";
3693 if(isset($_SESSION[COOKIENAME.'sortTables']))
3694 $orderTag = ($_SESSION[COOKIENAME.'sortTables']=="type" && $_SESSION[COOKIENAME.'orderTables']=="ASC") ? "DESC" : "ASC";
3695 else
3696 $orderTag = "ASC";
3697 echo "&order=".$orderTag;
3698 echo "'>".$lang['type']."</a> ".helpLink($lang['help3']);
3699 if(isset($_SESSION[COOKIENAME.'sortTables']) && $_SESSION[COOKIENAME.'sortTables']=="type")
3700 echo (($_SESSION[COOKIENAME.'orderTables']=="ASC") ? " <b>↑</b>" : " <b>↓</b>");
3701 echo "</td>";
3702
3703 echo "<td class='tdheader'>";
3704 echo "<a href='?sort=name";
3705 if(isset($_SESSION[COOKIENAME.'sortTables']))
3706 $orderTag = ($_SESSION[COOKIENAME.'sortTables']=="name" && $_SESSION[COOKIENAME.'orderTables']=="ASC") ? "DESC" : "ASC";
3707 else
3708 $orderTag = "ASC";
3709 echo "&order=".$orderTag;
3710 echo "'>".$lang['name']."</a>";
3711 if(isset($_SESSION[COOKIENAME.'sortTables']) && $_SESSION[COOKIENAME.'sortTables']=="name")
3712 echo (($_SESSION[COOKIENAME.'orderTables']=="ASC") ? " <b>↑</b>" : " <b>↓</b>");
3713 echo "</td>";
3714
3715 echo "<td class='tdheader' colspan='10'>".$lang['act']."</td>";
3716 echo "<td class='tdheader'>".$lang['rec']."</td>";
3717 echo "</tr>";
3718
3719 $totalRecords = 0;
3720 $skippedTables = false;
3721 for($i=0; $i<sizeof($result); $i++)
3722 {
3723 $records = $db->numRows($result[$i]['name'], (!isset($_GET['forceCount'])));
3724 if($records == '?')
3725 {
3726 $skippedTables = true;
3727 $records = "<a href='?forceCount=1'>?</a>";
3728 }
3729 else
3730 $totalRecords += $records;
3731 $tdWithClass = "<td class='td".($i%2 ? "1" : "2")."'>";
3732 $tdWithClassLeft = "<td class='td".($i%2 ? "1" : "2")."' style='text-align:left;'>";
3733
3734 if($result[$i]['type']=="table")
3735 {
3736 echo "<tr>";
3737 echo $tdWithClassLeft;
3738 echo $lang['tbl'];
3739 echo "</td>";
3740 echo $tdWithClassLeft;
3741 echo "<a href='?table=".urlencode($result[$i]['name'])."&action=row_view'>".htmlencode($result[$i]['name'])."</a>";
3742 echo "</td>";
3743 echo $tdWithClass;
3744 echo "<a href='?table=".urlencode($result[$i]['name'])."&action=row_view'>".$lang['browse']."</a>";
3745 echo "</td>";
3746 echo $tdWithClass;
3747 echo "<a href='?table=".urlencode($result[$i]['name'])."&action=column_view'>".$lang['struct']."</a>";
3748 echo "</td>";
3749 echo $tdWithClass;
3750 echo "<a href='?table=".urlencode($result[$i]['name'])."&action=table_sql'>".$lang['sql']."</a>";
3751 echo "</td>";
3752 echo $tdWithClass;
3753 echo "<a href='?table=".urlencode($result[$i]['name'])."&action=table_search'>".$lang['srch']."</a>";
3754 echo "</td>";
3755 echo $tdWithClass;
3756 echo "<a href='?table=".urlencode($result[$i]['name'])."&action=row_create'>".$lang['insert']."</a>";
3757 echo "</td>";
3758 echo $tdWithClass;
3759 echo "<a href='?table=".urlencode($result[$i]['name'])."&action=table_export'>".$lang['export']."</a>";
3760 echo "</td>";
3761 echo $tdWithClass;
3762 echo "<a href='?table=".urlencode($result[$i]['name'])."&action=table_import'>".$lang['import']."</a>";
3763 echo "</td>";
3764 echo $tdWithClass;
3765 echo "<a href='?table=".urlencode($result[$i]['name'])."&action=table_rename'>".$lang['rename']."</a>";
3766 echo "</td>";
3767 echo $tdWithClass;
3768 echo "<a href='?table=".urlencode($result[$i]['name'])."&action=table_empty' class='empty'>".$lang['empty']."</a>";
3769 echo "</td>";
3770 echo $tdWithClass;
3771 echo "<a href='?table=".urlencode($result[$i]['name'])."&action=table_drop' class='drop'>".$lang['drop']."</a>";
3772 echo "</td>";
3773 echo $tdWithClass;
3774 echo $records;
3775 echo "</td>";
3776 echo "</tr>";
3777 }
3778 else
3779 {
3780 echo "<tr>";
3781 echo $tdWithClassLeft;
3782 echo "View";
3783 echo "</td>";
3784 echo $tdWithClassLeft;
3785 echo "<a href='?table=".urlencode($result[$i]['name'])."&action=row_view'>".htmlencode($result[$i]['name'])."</a>";
3786 echo "</td>";
3787 echo $tdWithClass;
3788 echo "<a href='?table=".urlencode($result[$i]['name'])."&action=row_view'>".$lang['browse']."</a>";
3789 echo "</td>";
3790 echo $tdWithClass;
3791 echo "<a href='?table=".urlencode($result[$i]['name'])."&action=column_view'>".$lang['struct']."</a>";
3792 echo "</td>";
3793 echo $tdWithClass;
3794 echo "<a href='?table=".urlencode($result[$i]['name'])."&action=table_sql'>".$lang['sql']."</a>";
3795 echo "</td>";
3796 echo $tdWithClass;
3797 echo "<a href='?table=".urlencode($result[$i]['name'])."&action=table_search'>".$lang['srch']."</a>";
3798 echo "</td>";
3799 echo $tdWithClass;
3800 echo "";
3801 echo "</td>";
3802 echo $tdWithClass;
3803 echo "<a href='?table=".urlencode($result[$i]['name'])."&action=table_export'>".$lang['export']."</a>";
3804 echo "</td>";
3805 echo $tdWithClass;
3806 echo "";
3807 echo "</td>";
3808 echo $tdWithClass;
3809 echo "";
3810 echo "</td>";
3811 echo $tdWithClass;
3812 echo "";
3813 echo "</td>";
3814 echo $tdWithClass;
3815 echo "<a href='?table=".urlencode($result[$i]['name'])."&action=view_drop' class='drop'>".$lang['drop']."</a>";
3816 echo "</td>";
3817 echo $tdWithClass;
3818 echo $records;
3819 echo "</td>";
3820 echo "</tr>";
3821 }
3822 }
3823 echo "<tr>";
3824 echo "<td class='tdheader' colspan='12'>".sizeof($result)." ".$lang['total']."</td>";
3825 echo "<td class='tdheader' colspan='1' style='text-align:right;'>".$totalRecords.($skippedTables?" <a href='?forceCount=1'>+ ?</a>":"")."</td>";
3826 echo "</tr>";
3827 echo "</table>";
3828 echo "<br/>";
3829 if($skippedTables)
3830 echo "<div class='confirm' style='margin-bottom:20px;'>".sprintf($lang["counting_skipped"],"<a href='?forceCount=1'>","</a>")."</div>";
3831 }
3832 echo "<fieldset>";
3833 echo "<legend><b>".$lang['create_tbl_db']." '".htmlencode($db->getName())."'</b></legend>";
3834 echo "<form action='?action=table_create' method='post'>";
3835 echo $lang['name'].": <input type='text' name='tablename' style='width:200px;'/> ";
3836 echo $lang['fld_num'].": <input type='text' name='tablefields' style='width:90px;'/> ";
3837 echo "<input type='submit' name='createtable' value='".$lang['go']."' class='btn'/>";
3838 echo "</form>";
3839 echo "</fieldset>";
3840 echo "<br/>";
3841 echo "<fieldset>";
3842 echo "<legend><b>".$lang['create_view']." '".htmlencode($db->getName())."'</b></legend>";
3843 echo "<form action='?action=view_create&confirm=1' method='post'>";
3844 echo $lang['name'].": <input type='text' name='viewname' style='width:200px;'/> ";
3845 echo $lang['sel_state']." ".helpLink($lang['help4']).": <input type='text' name='select' style='width:400px;'/> ";
3846 echo "<input type='submit' name='createtable' value='".$lang['go']."' class='btn'/>";
3847 echo "</form>";
3848 echo "</fieldset>";
3849 }
3850 else if($view=="sql")
3851 {
3852 //- Database SQL editor (=sql)
3853 $isSelect = false;
3854 if(isset($_POST['query']) && $_POST['query']!="")
3855 {
3856 $delimiter = $_POST['delimiter'];
3857 $queryStr = $_POST['queryval'];
3858 //save the queries in history if necessary
3859 if($maxSavedQueries!=0 && $maxSavedQueries!=false)
3860 {
3861 if(!isset($_SESSION['query_history']))
3862 $_SESSION['query_history'] = array();
3863 $_SESSION['query_history'][md5(strtolower($queryStr))] = $queryStr;
3864 if(sizeof($_SESSION['query_history']) > $maxSavedQueries)
3865 array_shift($_SESSION['query_history']);
3866 }
3867 $query = explode_sql($delimiter, $queryStr); //explode the query string into individual queries based on the delimiter
3868
3869 for($i=0; $i<sizeof($query); $i++) //iterate through the queries exploded by the delimiter
3870 {
3871 if(str_replace(" ", "", str_replace("\n", "", str_replace("\r", "", $query[$i])))!="") //make sure this query is not an empty string
3872 {
3873 $queryTimer = new MicroTimer();
3874 $result = $db->selectArray($query[$i], "assoc");
3875 $queryTimer->stop();
3876
3877 echo "<div class='confirm'>";
3878 echo "<b>";
3879
3880 if($result !== NULL)
3881 {
3882
3883 if(sizeof($result)>0 || $db->getAffectedRows()==0)
3884 {
3885 printf($lang['show_rows'], sizeof($result));
3886 }
3887 if($db->getAffectedRows()>0 || sizeof($result)==0)
3888 {
3889 echo $db->getAffectedRows()." ".$lang['rows_aff']." ";
3890 }
3891 printf($lang['query_time'], $queryTimer);
3892 echo "</b><br/>";
3893 }
3894 else
3895 {
3896 echo $lang['err'].": ".$db->getError()."</b><br/>";
3897 }
3898 echo "<span style='font-size:11px;'>".htmlencode($query[$i])."</span>";
3899 echo "</div><br/>";
3900 if(sizeof($result)>0)
3901 {
3902 $headers = array_keys($result[0]);
3903
3904 echo "<table border='0' cellpadding='2' cellspacing='1' class='viewTable'>";
3905 echo "<tr>";
3906 for($j=0; $j<sizeof($headers); $j++)
3907 {
3908 echo "<td class='tdheader'>";
3909 echo htmlencode($headers[$j]);
3910 echo "</td>";
3911 }
3912 echo "</tr>";
3913 for($j=0; $j<sizeof($result); $j++)
3914 {
3915 $tdWithClass = "<td class='td".($j%2 ? "1" : "2")."'>";
3916 echo "<tr>";
3917 for($z=0; $z<sizeof($headers); $z++)
3918 {
3919 echo $tdWithClass;
3920 if($result[$j][$headers[$z]]==="")
3921 echo " ";
3922 elseif($result[$j][$headers[$z]]===NULL)
3923 echo "<i class='null'>NULL</i>";
3924 else
3925 echo htmlencode(subString($result[$j][$headers[$z]]));
3926 echo "</td>";
3927 }
3928 echo "</tr>";
3929 }
3930 echo "</table><br/><br/>";
3931 }
3932 }
3933 }
3934 }
3935 else
3936 {
3937 $delimiter = ";";
3938 $queryStr = "";
3939 }
3940
3941 echo "<fieldset>";
3942 echo "<legend><b>".sprintf($lang['run_sql'],htmlencode($db->getName()))."</b></legend>";
3943 echo "<form action='?view=sql' method='post'>";
3944 if(isset($_SESSION['query_history']) && sizeof($_SESSION['query_history'])>0)
3945 {
3946 echo "<b>".$lang['recent_queries']."</b><ul>";
3947 foreach($_SESSION['query_history'] as $key => $value)
3948 {
3949 echo "<li><a onclick='document.getElementById(\"queryval\").value = this.textContent;' href='#'>".htmlencode($value)."</a></li>";
3950 }
3951 echo "</ul><br/><br/>";
3952 }
3953 echo "<textarea style='width:100%; height:300px;' name='queryval' id='queryval' cols='50' rows='8'>".htmlencode($queryStr)."</textarea>";
3954 echo $lang['delimit']." <input type='text' name='delimiter' value='".htmlencode($delimiter)."' style='width:50px;'/> ";
3955 echo "<input type='submit' name='query' value='".$lang['go']."' class='btn'/>";
3956 echo "</form>";
3957 echo "</fieldset>";
3958 }
3959 else if($view=="vacuum")
3960 {
3961 //- Vacuum database confirmation (=vacuum)
3962 if(isset($_POST['vacuum']))
3963 {
3964 $query = "VACUUM";
3965 $db->query($query);
3966 echo "<div class='confirm'>";
3967 printf($lang['db_vac'], htmlencode($db->getName()));
3968 echo "</div><br/>";
3969 }
3970 echo "<form method='post' action='?view=vacuum'>";
3971 printf($lang['vac_desc'],htmlencode($db->getName()));
3972 echo "<br/><br/>";
3973 echo "<input type='submit' value='".$lang['vac']."' name='vacuum' class='btn'/>";
3974 echo "</form>";
3975 }
3976 else if($view=="export")
3977 {
3978 //- Export view (=export)
3979 echo "<form method='post' action='?view=export'>";
3980 echo "<fieldset style='float:left; width:260px; margin-right:20px;'><legend><b>".$lang['export']."</b></legend>";
3981 echo "<select multiple='multiple' size='10' style='width:240px;' name='tables[]'>";
3982 $query = "SELECT name FROM sqlite_master WHERE type='table' OR type='view' ORDER BY name";
3983 $result = $db->selectArray($query);
3984 for($i=0; $i<sizeof($result); $i++)
3985 {
3986 if(substr($result[$i]['name'], 0, 7)!="sqlite_" && $result[$i]['name']!="")
3987 echo "<option value='".htmlencode($result[$i]['name'])."' selected='selected'>".htmlencode($result[$i]['name'])."</option>";
3988 }
3989 echo "</select>";
3990 echo "<br/><br/>";
3991 echo "<label><input type='radio' name='export_type' checked='checked' value='sql' onclick='toggleExports(\"sql\");'/> ".$lang['sql']."</label>";
3992 echo "<br/><label><input type='radio' name='export_type' value='csv' onclick='toggleExports(\"csv\");'/> ".$lang['csv']."</label>";
3993 echo "</fieldset>";
3994
3995 echo "<fieldset style='float:left; max-width:350px;' id='exportoptions_sql'><legend><b>".$lang['options']."</b></legend>";
3996 echo "<label><input type='checkbox' checked='checked' name='structure'/> ".$lang['export_struct']."</label> ".helpLink($lang['help5'])."<br/>";
3997 echo "<label><input type='checkbox' checked='checked' name='data'/> ".$lang['export_data']."</label> ".helpLink($lang['help6'])."<br/>";
3998 echo "<label><input type='checkbox' name='drop'/> ".$lang['add_drop']."</label> ".helpLink($lang['help7'])."<br/>";
3999 echo "<label><input type='checkbox' checked='checked' name='transaction'/> ".$lang['add_transact']."</label> ".helpLink($lang['help8'])."<br/>";
4000 echo "<label><input type='checkbox' checked='checked' name='comments'/> ".$lang['comments']."</label> ".helpLink($lang['help9'])."<br/>";
4001 echo "</fieldset>";
4002
4003 echo "<fieldset style='float:left; max-width:350px; display:none;' id='exportoptions_csv'><legend><b>".$lang['options']."</b></legend>";
4004 echo "<div style='float:left;'>".$lang['fld_terminated']."</div>";
4005 echo "<input type='text' value=';' name='export_csv_fieldsterminated' style='float:right;'/>";
4006 echo "<div style='clear:both;'>";
4007 echo "<div style='float:left;'>".$lang['fld_enclosed']."</div>";
4008 echo "<input type='text' value='\"' name='export_csv_fieldsenclosed' style='float:right;'/>";
4009 echo "<div style='clear:both;'>";
4010 echo "<div style='float:left;'>".$lang['fld_escaped']."</div>";
4011 echo "<input type='text' value='\' name='export_csv_fieldsescaped' style='float:right;'/>";
4012 echo "<div style='clear:both;'>";
4013 echo "<div style='float:left;'>".$lang['rep_null']."</div>";
4014 echo "<input type='text' value='NULL' name='export_csv_replacenull' style='float:right;'/>";
4015 echo "<div style='clear:both;'>";
4016 echo "<label><input type='checkbox' name='export_csv_crlf'/> ".$lang['rem_crlf']."</label><br/>";
4017 echo "<label><input type='checkbox' checked='checked' name='export_csv_fieldnames'/> ".$lang['put_fld']."</label>";
4018 echo "</fieldset>";
4019
4020 echo "<div style='clear:both;'></div>";
4021 echo "<br/><br/>";
4022 echo "<fieldset><legend><b>".$lang['save_as']."</b></legend>";
4023 $file = pathinfo($db->getPath());
4024 $name = $file['filename'];
4025 echo "<input type='text' name='filename' value='".htmlencode($name)."_".date("Y-m-d").".dump' style='width:400px;'/> <input type='submit' name='export' value='".$lang['export']."' class='btn'/>";
4026 echo "</fieldset>";
4027 echo "</form>";
4028 echo "<div class='confirm' style='margin-top: 2em'>".sprintf($lang['backup_hint'], "<a href='?download=".urlencode($currentDB['path'])."' title='".$lang['backup']."'>".$lang["backup_hint_linktext"]."</a>")."</div>";
4029 }
4030 else if($view=="import")
4031 {
4032 //- Import view (=import)
4033 if(isset($_POST['import']))
4034 {
4035 echo "<div class='confirm'>";
4036 if($importSuccess===true)
4037 echo $lang['import_suc'];
4038 else
4039 echo $importSuccess;
4040 echo "</div><br/>";
4041 }
4042
4043 echo "<form method='post' action='?view=import' enctype='multipart/form-data'>";
4044 echo "<fieldset style='float:left; width:260px; margin-right:20px;'><legend><b>".$lang['import']."</b></legend>";
4045 echo "<label><input type='radio' name='import_type' checked='checked' value='sql' onclick='toggleImports(\"sql\");'/> ".$lang['sql']."</label>";
4046 echo "<br/><label><input type='radio' name='import_type' value='csv' onclick='toggleImports(\"csv\");'/> ".$lang['csv']."</label>";
4047 echo "</fieldset>";
4048
4049 echo "<fieldset style='float:left; max-width:350px;' id='importoptions_sql'><legend><b>".$lang['options']."</b></legend>";
4050 echo $lang['no_opt'];
4051 echo "</fieldset>";
4052
4053 echo "<fieldset style='float:left; max-width:350px; display:none;' id='importoptions_csv'><legend><b>".$lang['options']."</b></legend>";
4054 echo "<div style='float:left;'>".$lang['csv_tbl']."</div>";
4055 echo "<select name='single_table' style='float:right;'>";
4056 $query = "SELECT name FROM sqlite_master WHERE type='table' OR type='view' ORDER BY name";
4057 $result = $db->selectArray($query);
4058 for($i=0; $i<sizeof($result); $i++)
4059 {
4060 if(substr($result[$i]['name'], 0, 7)!="sqlite_" && $result[$i]['name']!="")
4061 echo "<option value='".htmlencode($result[$i]['name'])."'>".htmlencode($result[$i]['name'])."</option>";
4062 }
4063 echo "</select>";
4064 echo "<div style='clear:both;'>";
4065 echo "<div style='float:left;'>".$lang['fld_terminated']."</div>";
4066 echo "<input type='text' value=';' name='import_csv_fieldsterminated' style='float:right;'/>";
4067 echo "<div style='clear:both;'>";
4068 echo "<div style='float:left;'>".$lang['fld_enclosed']."</div>";
4069 echo "<input type='text' value='\"' name='import_csv_fieldsenclosed' style='float:right;'/>";
4070 echo "<div style='clear:both;'>";
4071 echo "<div style='float:left;'>".$lang['fld_escaped']."</div>";
4072 echo "<input type='text' value='\' name='import_csv_fieldsescaped' style='float:right;'/>";
4073 echo "<div style='clear:both;'>";
4074 echo "<div style='float:left;'>".$lang['null_represent']."</div>";
4075 echo "<input type='text' value='NULL' name='import_csv_replacenull' style='float:right;'/>";
4076 echo "<div style='clear:both;'>";
4077 echo "<label><input type='checkbox' checked='checked' name='import_csv_fieldnames'/> ".$lang['fld_names']."</label>";
4078 echo "</fieldset>";
4079
4080 echo "<div style='clear:both;'></div>";
4081 echo "<br/><br/>";
4082
4083 echo "<fieldset><legend><b>".$lang['import_f']."</b></legend>";
4084 echo "<input type='file' value='".$lang['choose_f']."' name='file' style='background-color:transparent; border-style:none;'/> <input type='submit' value='".$lang['import']."' name='import' class='btn'/>";
4085 echo "</fieldset>";
4086 }
4087 else if($view=="rename")
4088 {
4089 //- Rename database confirmation (=rename)
4090 if(isset($extension_not_allowed))
4091 {
4092 echo "<div class='confirm'>";
4093 echo $lang['extension_not_allowed'].': ';
4094 echo implode(', ', array_map('htmlencode', $allowed_extensions));
4095 echo '<br />'.$lang['add_allowed_extension'];
4096 echo "</div><br/>";
4097 }
4098 if(isset($dbexists))
4099 {
4100 echo "<div class='confirm'>";
4101 if($oldpath==$newpath)
4102 echo $lang['err'].": ".$lang['warn_dumbass'];
4103 else{
4104 echo $lang['err'].": ";
4105 printf($lang['db_exists'], htmlencode($newpath));
4106 }
4107 echo "</div><br/>";
4108 }
4109 if(isset($justrenamed))
4110 {
4111 echo "<div class='confirm'>";
4112 printf($lang['db_renamed'], htmlencode($oldpath));
4113 echo " '".htmlencode($newpath)."'.";
4114 echo "</div><br/>";
4115 }
4116 echo "<form action='?view=rename&database_rename=1' method='post'>";
4117 echo "<input type='hidden' name='oldname' value='".htmlencode($db->getPath())."'/>";
4118 echo $lang['db_rename']." '".htmlencode($db->getPath())."' ".$lang['to']." <input type='text' name='newname' style='width:200px;' value='".htmlencode($db->getPath())."'/> <input type='submit' value='".$lang['rename']."' name='rename' class='btn'/>";
4119 echo "</form>";
4120 }
4121 else if($view=="delete")
4122 {
4123 //- Delete database confirmation (=delete)
4124 echo "<form action='?database_delete=1' method='post'>";
4125 echo "<div class='confirm'>";
4126 echo sprintf($lang['ques_del_db'],htmlencode($db->getPath()))."<br/><br/>";
4127 echo "<input name='database_delete' value='".htmlencode($db->getPath())."' type='hidden'/>";
4128 echo "<input type='submit' value='".$lang['confirm']."' class='btn'/> ";
4129 echo "<a href='".PAGE."'>".$lang['cancel']."</a>";
4130 echo "</div>";
4131 echo "</form>";
4132 }
4133
4134 echo "</div>";
4135}
4136
4137//- HTML: page footer
4138echo "<br/>";
4139echo "<span style='font-size:11px;'>".$lang['powered']." <a href='".PROJECT_URL."' target='_blank' style='font-size:11px;'>".PROJECT."</a> | ";
4140echo $lang['free_software']." <a href='".DONATE_URL."' target='_blank' style='font-size:11px;'>".$lang['please_donate']."</a> | ";
4141printf($lang['page_gen'], $pageTimer);
4142echo "</span>";
4143echo "</td></tr></table>";
4144$db->close(); //close the database
4145echo "</body>";
4146echo "</html>";
4147
4148//- End of main code
4149
4150// Authorization class
4151// Maintains user's logged-in state and security of application
4152//
4153class Authorization
4154{
4155 private $authorized;
4156 private $login_failed;
4157 private $system_password_encrypted;
4158
4159 public function __construct()
4160 {
4161 // the salt and password encrypting is probably unnecessary protection but is done just
4162 // for the sake of being very secure
4163 if(!isset($_SESSION[COOKIENAME.'_salt']) && !isset($_COOKIE[COOKIENAME.'_salt']))
4164 {
4165 // create a random salt for this session if a cookie doesn't already exist for it
4166 $_SESSION[COOKIENAME.'_salt'] = self::generateSalt(20);
4167 }
4168 else if(!isset($_SESSION[COOKIENAME.'_salt']) && isset($_COOKIE[COOKIENAME.'_salt']))
4169 {
4170 // session doesn't exist, but cookie does so grab it
4171 $_SESSION[COOKIENAME.'_salt'] = $_COOKIE[COOKIENAME.'_salt'];
4172 }
4173
4174 // salted and encrypted password used for checking
4175 $this->system_password_encrypted = md5(SYSTEMPASSWORD."_".$_SESSION[COOKIENAME.'_salt']);
4176
4177 $this->authorized =
4178 // no password
4179 SYSTEMPASSWORD == ''
4180 // correct password stored in session
4181 || isset($_SESSION[COOKIENAME.'password']) && $_SESSION[COOKIENAME.'password'] == $this->system_password_encrypted
4182 // correct password stored in cookie
4183 || isset($_COOKIE[COOKIENAME]) && isset($_COOKIE[COOKIENAME.'_salt']) && md5(SYSTEMPASSWORD."_".$_COOKIE[COOKIENAME.'_salt']) == $_COOKIE[COOKIENAME];
4184 }
4185
4186 public function attemptGrant($password, $remember)
4187 {
4188 if ($password == SYSTEMPASSWORD) {
4189 if ($remember) {
4190 // user wants to be remembered, so set a cookie
4191 $expire = time()+60*60*24*30; //set expiration to 1 month from now
4192 setcookie(COOKIENAME, $this->system_password_encrypted, $expire, null, null, null, true);
4193 setcookie(COOKIENAME."_salt", $_SESSION[COOKIENAME.'_salt'], $expire, null, null, null, true);
4194 } else {
4195 // user does not want to be remembered, so destroy any potential cookies
4196 setcookie(COOKIENAME, "", time()-86400, null, null, null, true);
4197 setcookie(COOKIENAME."_salt", "", time()-86400, null, null, null, true);
4198 unset($_COOKIE[COOKIENAME]);
4199 unset($_COOKIE[COOKIENAME.'_salt']);
4200 }
4201
4202 $_SESSION[COOKIENAME.'password'] = $this->system_password_encrypted;
4203 $this->authorized = true;
4204 return true;
4205 }
4206
4207 $this->login_failed = true;
4208 return false;
4209 }
4210
4211 public function revoke()
4212 {
4213 //destroy everything - cookies and session vars
4214 setcookie(COOKIENAME, "", time()-86400, null, null, null, true);
4215 setcookie(COOKIENAME."_salt", "", time()-86400, null, null, null, true);
4216 unset($_COOKIE[COOKIENAME]);
4217 unset($_COOKIE[COOKIENAME.'_salt']);
4218 session_unset();
4219 session_destroy();
4220 $this->authorized = false;
4221 }
4222
4223 public function isAuthorized()
4224 {
4225 return $this->authorized;
4226 }
4227
4228 public function isFailedLogin()
4229 {
4230 return $this->login_failed;
4231 }
4232
4233 public function isPasswordDefault()
4234 {
4235 return SYSTEMPASSWORD == 'asdfghj';
4236 }
4237
4238 private static function generateSalt($saltSize)
4239 {
4240 $set = 'ABCDEFGHiJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
4241 $setLast = strlen($set) - 1;
4242 $salt = '';
4243 while ($saltSize-- > 0) {
4244 $salt .= $set[mt_rand(0, $setLast)];
4245 }
4246 return $salt;
4247 }
4248
4249}
4250// Database class
4251// Generic database abstraction class to manage interaction with database without worrying about SQLite vs. PHP versions
4252//
4253class Database
4254{
4255 protected $db; //reference to the DB object
4256 protected $type; //the extension for PHP that handles SQLite
4257 protected $data;
4258 protected $lastResult;
4259 protected $alterError;
4260
4261 public function __construct($data)
4262 {
4263 global $lang;
4264 $this->data = $data;
4265 try
4266 {
4267 if(!file_exists($this->data["path"]) && !is_writable(dirname($this->data["path"]))) //make sure the containing directory is writable if the database does not exist
4268 {
4269 echo "<div class='confirm' style='margin:20px;'>";
4270 printf($lang['db_not_writeable'], htmlencode($this->data["path"]), htmlencode(dirname($this->data["path"])));
4271 echo "<form action='".PAGE."' method='post'>";
4272 echo "<input type='submit' value='Log Out' name='".$lang['logout']."' class='btn'/>";
4273 echo "</form>";
4274 echo "</div><br/>";
4275 exit();
4276 }
4277
4278 $ver = $this->getVersion();
4279
4280 switch(true)
4281 {
4282 case (FORCETYPE=="PDO" || ((FORCETYPE==false || $ver!=-1) && class_exists("PDO") && ($ver==-1 || $ver==3))):
4283 $this->db = new PDO("sqlite:".$this->data['path']);
4284 if($this->db!=NULL)
4285 {
4286 $this->type = "PDO";
4287 break;
4288 }
4289 case (FORCETYPE=="SQLite3" || ((FORCETYPE==false || $ver!=-1) && class_exists("SQLite3") && ($ver==-1 || $ver==3))):
4290 $this->db = new SQLite3($this->data['path']);
4291 if($this->db!=NULL)
4292 {
4293 $this->type = "SQLite3";
4294 break;
4295 }
4296 case (FORCETYPE=="SQLiteDatabase" || ((FORCETYPE==false || $ver!=-1) && class_exists("SQLiteDatabase") && ($ver==-1 || $ver==2))):
4297 $this->db = new SQLiteDatabase($this->data['path']);
4298 if($this->db!=NULL)
4299 {
4300 $this->type = "SQLiteDatabase";
4301 break;
4302 }
4303 default:
4304 $this->showError();
4305 exit();
4306 }
4307 }
4308 catch(Exception $e)
4309 {
4310 $this->showError();
4311 exit();
4312 }
4313 }
4314
4315 public function registerUserFunction($ids)
4316 {
4317 // in case a single function id was passed
4318 if (is_string($ids))
4319 $ids = array($ids);
4320
4321 if ($this->type == 'PDO') {
4322 foreach ($ids as $id) {
4323 $this->db->sqliteCreateFunction($id, $id, 1);
4324 }
4325 } else { // type is Sqlite3 or SQLiteDatabase
4326 foreach ($ids as $id) {
4327 $this->db->createFunction($id, $id, 1);
4328 }
4329 }
4330 }
4331
4332 public function getError()
4333 {
4334 if($this->alterError!='')
4335 {
4336 $error = $this->alterError;
4337 $this->alterError = "";
4338 return $error;
4339 }
4340 else if($this->type=="PDO")
4341 {
4342 $e = $this->db->errorInfo();
4343 return $e[2];
4344 }
4345 else if($this->type=="SQLite3")
4346 {
4347 return $this->db->lastErrorMsg();
4348 }
4349 else
4350 {
4351 return sqlite_error_string($this->db->lastError());
4352 }
4353 }
4354
4355 public function showError()
4356 {
4357 global $lang;
4358 $classPDO = class_exists("PDO");
4359 $classSQLite3 = class_exists("SQLite3");
4360 $classSQLiteDatabase = class_exists("SQLiteDatabase");
4361 if($classPDO) // PDO is there, check if the SQLite driver for PDO is missing
4362 $PDOSqliteDriver = (in_array("sqlite", PDO::getAvailableDrivers() ));
4363 else
4364 $PDOSqliteDriver = false;
4365 echo "<div class='confirm' style='margin:20px;'>";
4366 printf($lang['db_setup'], $this->getPath());
4367 echo ".<br/><br/><i>".$lang['chk_ext']."...<br/><br/>";
4368 echo "<b>PDO</b>: ".($classPDO ? $lang['installed'] : $lang['not_installed'])."<br/>";
4369 echo "<b>PDO SQLite Driver</b>: ".($PDOSqliteDriver ? $lang['installed'] : $lang['not_installed'])."<br/>";
4370 echo "<b>SQLite3</b>: ".($classSQLite3 ? $lang['installed'] : $lang['not_installed'])."<br/>";
4371 echo "<b>SQLiteDatabase</b>: ".($classSQLiteDatabase ? $lang['installed'] : $lang['not_installed'])."<br/>";
4372 echo "<br/>...".$lang['done'].".</i><br/><br/>";
4373 if(!$classPDO && !$classSQLite3 && !$classSQLiteDatabase)
4374 printf($lang['sqlite_ext_support'], PROJECT);
4375 else
4376 {
4377 if(!$classPDO && !$classSQLite3 && $this->getVersion()==3)
4378 printf($lang['sqlite_v_error'], 3, PROJECT, 2);
4379 else if(!$classSQLiteDatabase && $this->getVersion()==2)
4380 printf($lang['sqlite_v_error'], 2, PROJECT, 3);
4381 else
4382 echo $lang['report_issue'].' '.PROJECT_BUGTRACKER_LINK.'.';
4383 }
4384 echo "<br />See ".PROJECT_INSTALL_LINK." for help.";
4385 echo "</div><br/>";
4386 }
4387
4388 public function __destruct()
4389 {
4390 if($this->db)
4391 $this->close();
4392 }
4393
4394 //get the exact PHP extension being used for SQLite
4395 public function getType()
4396 {
4397 return $this->type;
4398 }
4399
4400 //get the name of the database
4401 public function getName()
4402 {
4403 return $this->data["name"];
4404 }
4405
4406 //get the filename of the database
4407 public function getPath()
4408 {
4409 return $this->data["path"];
4410 }
4411
4412 //is the db-file writable?
4413 public function isWritable()
4414 {
4415 return $this->data["writable"];
4416 }
4417
4418 //is the db-folder writable?
4419 public function isDirWritable()
4420 {
4421 return $this->data["writable_dir"];
4422 }
4423
4424 //get the version of the database
4425 public function getVersion()
4426 {
4427 if(file_exists($this->data['path'])) //make sure file exists before getting its contents
4428 {
4429 $content = strtolower(file_get_contents($this->data['path'], NULL, NULL, 0, 40)); //get the first 40 characters of the database file
4430 $p = strpos($content, "** this file contains an sqlite 2"); //this text is at the beginning of every SQLite2 database
4431 if($p!==false) //the text is found - this is version 2
4432 return 2;
4433 else
4434 return 3;
4435 }
4436 else //return -1 to indicate that it does not exist and needs to be created
4437 {
4438 return -1;
4439 }
4440 }
4441
4442 //get the size of the database (in KB)
4443 public function getSize()
4444 {
4445 return round(filesize($this->data["path"])*0.0009765625, 1);
4446 }
4447
4448 //get the last modified time of database
4449 public function getDate()
4450 {
4451 global $lang;
4452 return date($lang['date_format'], filemtime($this->data['path']));
4453 }
4454
4455 //get number of affected rows from last query
4456 public function getAffectedRows()
4457 {
4458 if($this->type=="PDO")
4459 if(!is_object($this->lastResult))
4460 // in case it was an alter table statement, there is no lastResult object
4461 return 0;
4462 else
4463 return $this->lastResult->rowCount();
4464 else if($this->type=="SQLite3")
4465 return $this->db->changes();
4466 else if($this->type=="SQLiteDatabase")
4467 return $this->db->changes();
4468 }
4469
4470 public function getTypeOfTable($table)
4471 {
4472 $result = $this->select("SELECT `type` FROM `sqlite_master` WHERE `name`=" . $this->quote($table), 'assoc');
4473 return $result['type'];
4474 }
4475
4476 public function close()
4477 {
4478 if($this->type=="PDO")
4479 $this->db = NULL;
4480 else if($this->type=="SQLite3")
4481 $this->db->close();
4482 else if($this->type=="SQLiteDatabase")
4483 $this->db = NULL;
4484 }
4485
4486 public function beginTransaction()
4487 {
4488 $this->query("BEGIN");
4489 }
4490
4491 public function commitTransaction()
4492 {
4493 $this->query("COMMIT");
4494 }
4495
4496 public function rollbackTransaction()
4497 {
4498 $this->query("ROLLBACK");
4499 }
4500
4501 //generic query wrapper
4502 //returns false on error and the query result on success
4503 public function query($query, $ignoreAlterCase=false)
4504 {
4505 global $debug;
4506 if(strtolower(substr(ltrim($query),0,5))=='alter' && $ignoreAlterCase==false) //this query is an ALTER query - call the necessary function
4507 {
4508 preg_match("/^\s*ALTER\s+TABLE\s+\"((?:[^\"]|\"\")+)\"\s+(.*)$/i",$query,$matches);
4509 if(!isset($matches[1]) || !isset($matches[2]))
4510 {
4511 if($debug) echo "<span title='".htmlencode($query)."' onclick='this.innerHTML=\"".htmlencode(str_replace('"','\"',$query))."\"' style='cursor:pointer'>SQL?</span><br />";
4512 return false;
4513 }
4514 $tablename = str_replace('""','"',$matches[1]);
4515 $alterdefs = $matches[2];
4516 if($debug) echo "ALTER TABLE QUERY=(".htmlencode($query)."), tablename=($tablename), alterdefs=($alterdefs)<hr>";
4517 $result = $this->alterTable($tablename, $alterdefs);
4518 }
4519 else //this query is normal - proceed as normal
4520 {
4521 $result = $this->db->query($query);
4522 if($debug) echo "<span title='".htmlencode($query)."' onclick='this.innerHTML=\"".htmlencode(str_replace('"','\"',$query))."\"' style='cursor:pointer'>SQL?</span><br />";
4523 }
4524 if($result===false)
4525 return false;
4526 $this->lastResult = $result;
4527 return $result;
4528 }
4529
4530 //wrapper for an INSERT and returns the ID of the inserted row
4531 public function insert($query)
4532 {
4533 $result = $this->query($query);
4534 if($this->type=="PDO")
4535 return $this->db->lastInsertId();
4536 else if($this->type=="SQLite3")
4537 return $this->db->lastInsertRowID();
4538 else if($this->type=="SQLiteDatabase")
4539 return $this->db->lastInsertRowid();
4540 }
4541
4542 //returns an array for SELECT
4543 public function select($query, $mode="both")
4544 {
4545 $result = $this->query($query);
4546 if(!$result) //make sure the result is valid
4547 return NULL;
4548 if($this->type=="PDO")
4549 {
4550 if($mode=="assoc")
4551 $mode = PDO::FETCH_ASSOC;
4552 else if($mode=="num")
4553 $mode = PDO::FETCH_NUM;
4554 else
4555 $mode = PDO::FETCH_BOTH;
4556 return $result->fetch($mode);
4557 }
4558 else if($this->type=="SQLite3")
4559 {
4560 if($mode=="assoc")
4561 $mode = SQLITE3_ASSOC;
4562 else if($mode=="num")
4563 $mode = SQLITE3_NUM;
4564 else
4565 $mode = SQLITE3_BOTH;
4566 return $result->fetchArray($mode);
4567 }
4568 else if($this->type=="SQLiteDatabase")
4569 {
4570 if($mode=="assoc")
4571 $mode = SQLITE_ASSOC;
4572 else if($mode=="num")
4573 $mode = SQLITE_NUM;
4574 else
4575 $mode = SQLITE_BOTH;
4576 return $result->fetch($mode);
4577 }
4578 }
4579
4580 //returns an array of arrays after doing a SELECT
4581 public function selectArray($query, $mode="both")
4582 {
4583 $result = $this->query($query);
4584 //make sure the result is valid
4585 if($result=== false || $result===NULL)
4586 return NULL; // error
4587 if(!is_object($result)) // no rows returned
4588 return array();
4589 if($this->type=="PDO")
4590 {
4591 if($mode=="assoc")
4592 $mode = PDO::FETCH_ASSOC;
4593 else if($mode=="num")
4594 $mode = PDO::FETCH_NUM;
4595 else
4596 $mode = PDO::FETCH_BOTH;
4597 return $result->fetchAll($mode);
4598 }
4599 else if($this->type=="SQLite3")
4600 {
4601 if($mode=="assoc")
4602 $mode = SQLITE3_ASSOC;
4603 else if($mode=="num")
4604 $mode = SQLITE3_NUM;
4605 else
4606 $mode = SQLITE3_BOTH;
4607 $arr = array();
4608 $i = 0;
4609 while($res = $result->fetchArray($mode))
4610 {
4611 $arr[$i] = $res;
4612 $i++;
4613 }
4614 return $arr;
4615 }
4616 else if($this->type=="SQLiteDatabase")
4617 {
4618 if($mode=="assoc")
4619 $mode = SQLITE_ASSOC;
4620 else if($mode=="num")
4621 $mode = SQLITE_NUM;
4622 else
4623 $mode = SQLITE_BOTH;
4624 return $result->fetchAll($mode);
4625 }
4626 }
4627
4628
4629 // SQlite supports multiple ways of surrounding names in quotes:
4630 // single-quotes, double-quotes, backticks, square brackets.
4631 // As sqlite does not keep this strict, we also need to be flexible here.
4632 // This function generates a regex that matches any of the possibilities.
4633 private function sqlite_surroundings_preg($name,$preg_quote=true,$notAllowedCharsIfNone="'\"",$notAllowedName=false)
4634 {
4635 if($name=="*" || $name=="+")
4636 {
4637 if($notAllowedName!==false && $preg_quote)
4638 $notAllowedName = preg_quote($notAllowedName,"/");
4639 // use possesive quantifiers to save memory
4640 $nameSingle = ($notAllowedName!==false?"(?!".$notAllowedName."')":"")."(?:[^']$name+|'')$name+";
4641 $nameDouble = ($notAllowedName!==false?"(?!".$notAllowedName."\")":"")."(?:[^\"]$name+|\"\")$name+";
4642 $nameBacktick = ($notAllowedName!==false?"(?!".$notAllowedName."`)":"")."(?:[^`]$name+|``)$name+";
4643 $nameSquare = ($notAllowedName!==false?"(?!".$notAllowedName."\])":"")."(?:[^\]]$name+|\]\])$name+";
4644 $nameNo = ($notAllowedName!==false?"(?!".$notAllowedName."\s)":"")."[^".$notAllowedCharsIfNone."]$name";
4645 }
4646 else
4647 {
4648 if($preg_quote) $name = preg_quote($name,"/");
4649
4650 $nameSingle = str_replace("'","''",$name);
4651 $nameDouble = str_replace('"','""',$name);
4652 $nameBacktick = str_replace('`','``',$name);
4653 $nameSquare = str_replace(']',']]',$name);
4654 $nameNo = $name;
4655 }
4656
4657 $preg = "(?:'".$nameSingle."'|". // single-quote surrounded or not in quotes (correct SQL for values/new names)
4658 $nameNo."|". // not surrounded (correct SQL if not containing reserved words, spaces or some special chars)
4659 "\"".$nameDouble."\"|". // double-quote surrounded (correct SQL for identifiers)
4660 "`".$nameBacktick."`|". // backtick surrounded (MySQL-Style)
4661 "\[".$nameSquare."\])"; // square-bracket surrounded (MS Access/SQL server-Style)
4662 return $preg;
4663 }
4664
4665 // Returns the last PREG error as a string, '' if no error occured
4666 private function getPregError()
4667 {
4668 $error = preg_last_error();
4669 switch ($error)
4670 {
4671 case PREG_NO_ERROR: return 'No error';
4672 case PREG_INTERNAL_ERROR: return 'There is an internal error!';
4673 case PREG_BACKTRACK_LIMIT_ERROR: return 'Backtrack limit was exhausted!';
4674 case PREG_RECURSION_LIMIT_ERROR: return 'Recursion limit was exhausted!';
4675 case PREG_BAD_UTF8_ERROR: return 'Bad UTF8 error!';
4676 case PREG_BAD_UTF8_ERROR: return 'Bad UTF8 offset error!';
4677 default: return 'Unknown Error';
4678 }
4679 }
4680
4681 // function that is called for an alter table statement in a query
4682 // code borrowed with permission from http://code.jenseng.com/db/
4683 // this has been completely debugged / rewritten by Christopher Kramer
4684 public function alterTable($table, $alterdefs)
4685 {
4686 global $debug, $lang;
4687 $this->alterError="";
4688 $errormsg = sprintf($lang['alter_failed'],htmlencode($table)).' - ';
4689 if($debug) echo "ALTER TABLE: table=($table), alterdefs=($alterdefs)<hr>";
4690 if($alterdefs != '')
4691 {
4692 $recreateQueries = array();
4693 $resultArr = $this->selectArray("SELECT sql,name,type FROM sqlite_master WHERE tbl_name = ".$this->quote($table));
4694 if(sizeof($resultArr)<1)
4695 {
4696 $this->alterError = $errormsg . sprintf($lang['tbl_inexistent'], htmlencode($table));
4697 if($debug) echo "ERROR: unknown table<hr>";
4698 return false;
4699 }
4700 for($i=0; $i<sizeof($resultArr); $i++)
4701 {
4702 $row = $resultArr[$i];
4703 if($row['type'] != 'table')
4704 {
4705 if($row['sql']!='')
4706 {
4707 // store the CREATE statements of triggers and indexes to recreate them later
4708 $recreateQueries[] = $row;
4709 if($debug) echo "recreate=(".$row['sql'].";)<hr />";
4710 }
4711 }
4712 else
4713 {
4714 // ALTER the table
4715 $tmpname = 't'.time();
4716 $origsql = $row['sql'];
4717 $preg_remove_create_table = "/^\s*+CREATE\s++TABLE\s++".$this->sqlite_surroundings_preg($table)."\s*+(\(.*+)$/is";
4718 $origsql_no_create = preg_replace($preg_remove_create_table, '$1', $origsql, 1);
4719 if($debug) echo "origsql=($origsql)<br />preg_remove_create_table=($preg_remove_create_table)<hr>";
4720 if($origsql_no_create == $origsql)
4721 {
4722 $this->alterError = $errormsg . $lang['alter_tbl_name_not_replacable'];
4723 if($debug) echo "ERROR: could not get rid of CREATE TABLE<hr />";
4724 return false;
4725 }
4726 $createtemptableSQL = "CREATE TEMPORARY TABLE ".$this->quote($tmpname)." ".$origsql_no_create;
4727 if($debug) echo "createtemptableSQL=($createtemptableSQL)<hr>";
4728 $createindexsql = array();
4729 $preg_alter_part = "/(?:DROP(?! PRIMARY KEY)|ADD(?! PRIMARY KEY)|CHANGE|RENAME TO|ADD PRIMARY KEY|DROP PRIMARY KEY)" // the ALTER command
4730 ."(?:"
4731 ."\s+\(".$this->sqlite_surroundings_preg("+",false,"\"'\[`)")."+\)" // stuff in brackets (in case of ADD PRIMARY KEY)
4732 ."|" // or
4733 ."\s+".$this->sqlite_surroundings_preg("+",false,",'\"\[`") // column names and stuff like this
4734 .")*/i";
4735 if($debug)
4736 echo "preg_alter_part=(".$preg_alter_part.")<hr />";
4737 preg_match_all($preg_alter_part,$alterdefs,$matches);
4738 $defs = $matches[0];
4739
4740 $get_oldcols_query = "PRAGMA table_info(".$this->quote_id($table).")";
4741 $result_oldcols = $this->selectArray($get_oldcols_query);
4742 $newcols = array();
4743 $coltypes = array();
4744 $primarykey = array();
4745 foreach($result_oldcols as $column_info)
4746 {
4747 $newcols[$column_info['name']] = $column_info['name'];
4748 $coltypes[$column_info['name']] = $column_info['type'];
4749 if($column_info['pk'])
4750 $primarykey[] = $column_info['name'];
4751 }
4752 $newcolumns = '';
4753 $oldcolumns = '';
4754 reset($newcols);
4755 while(list($key, $val) = each($newcols))
4756 {
4757 $newcolumns .= ($newcolumns?', ':'').$this->quote_id($val);
4758 $oldcolumns .= ($oldcolumns?', ':'').$this->quote_id($key);
4759 }
4760 $copytotempsql = 'INSERT INTO '.$this->quote_id($tmpname).'('.$newcolumns.') SELECT '.$oldcolumns.' FROM '.$this->quote_id($table);
4761 $dropoldsql = 'DROP TABLE '.$this->quote_id($table);
4762 $createtesttableSQL = $createtemptableSQL;
4763 if(count($defs)<1)
4764 {
4765 $this->alterError = $errormsg . $lang['alter_no_def'];
4766 if($debug) echo "ERROR: defs<1<hr />";
4767 return false;
4768 }
4769 foreach($defs as $def)
4770 {
4771 if($debug) echo "def=$def<hr />";
4772 $preg_parse_def =
4773 "/^(DROP(?! PRIMARY KEY)|ADD(?! PRIMARY KEY)|CHANGE|RENAME TO|ADD PRIMARY KEY|DROP PRIMARY KEY)" // $matches[1]: command
4774 ."(?:" // this is either
4775 ."(?:\s+\((.+)\)\s*$)" // anything in brackets (for ADD PRIMARY KEY)
4776 // then $matches[2] is what there is in brackets
4777 ."|" // OR:
4778 ."(?:\s+\"((?:[^\"]|\"\")+)\"|\s+'((?:[^']|'')+)')"// (first) column name, either in single or double quotes
4779 // in case of RENAME TO, it is the new a table name
4780 // $matches[3] will be the column/table name without the quotes if double quoted
4781 // $matches[4] will be the column/table name without the quotes if single quoted
4782 ."(" // $matches[5]: anything after the column name
4783 ."(?:\s+'((?:[^']|'')+)')?" // $matches[6] (optional): a second column name surrounded with single quotes
4784 // (the match does not contain the quotes)
4785 ."\s+"
4786 ."((?:[A-Z]+\s*)+(?:\(\s*[+-]?\s*[0-9]+(?:\s*,\s*[+-]?\s*[0-9]+)?\s*\))?)\s*" // $matches[7]: a type name
4787 .".*".
4788 ")"
4789 ."?\s*$"
4790 .")?\s*$/i"; // in case of DROP PRIMARY KEY, there is nothing after the command
4791 if($debug) echo "preg_parse_def=$preg_parse_def<hr />";
4792 $parse_def = preg_match($preg_parse_def,$def,$matches);
4793 if($parse_def===false)
4794 {
4795 $this->alterError = $errormsg . $lang['alter_parse_failed'];
4796 if($debug) echo "ERROR: !parse_def<hr />";
4797 return false;
4798 }
4799 if(!isset($matches[1]))
4800 {
4801 $this->alterError = $errormsg . $lang['alter_action_not_recognized'];
4802 if($debug) echo "ERROR: !isset(matches[1])<hr />";
4803 return false;
4804 }
4805 $action = strtolower($matches[1]);
4806 if(($action == 'add' || $action == 'rename to') && isset($matches[4]) && $matches[4]!='')
4807 $column = str_replace("''","'",$matches[4]); // enclosed in ''
4808 elseif($action == 'add primary key' && isset($matches[2]) && $matches[2]!='')
4809 $column = $matches[2];
4810 elseif($action == 'drop primary key')
4811 $column = ''; // DROP PRIMARY KEY has no column definition
4812 elseif(isset($matches[3]) && $matches[3]!='')
4813 $column = str_replace('""','"',$matches[3]); // enclosed in ""
4814 else
4815 $column = '';
4816
4817 $column_escaped = str_replace("'","''",$column);
4818
4819 if($debug) echo "action=($action), column=($column), column_escaped=($column_escaped)<hr />";
4820
4821 /* we build a regex that devides the CREATE TABLE statement parts:
4822 Part example Group Explanation
4823 1. CREATE TABLE t... ( $1
4824 2. 'col1' ..., 'col2' ..., 'colN' ..., $3 (with col1-colN being columns that are not changed and listed before the col to change)
4825 3. 'colX' ..., (with colX being the column to change/drop)
4826 4. 'colX+1' ..., ..., 'colK') $5 (with colX+1-colK being columns after the column to change/drop)
4827 */
4828 $preg_create_table = "\s*+(CREATE\s++TEMPORARY\s++TABLE\s++".preg_quote($this->quote($tmpname),"/")."\s*+\()"; // This is group $1 (keep unchanged)
4829 $preg_column_definiton = "\s*+".$this->sqlite_surroundings_preg("+",true," '\"\[`,",$column)."(?:\s*+".$this->sqlite_surroundings_preg("*",false,"'\",`\[ ").")++"; // catches a complete column definition, even if it is
4830 // 'column' TEXT NOT NULL DEFAULT 'we have a comma, here and a double ''quote!'
4831 // this definition does NOT match columns with the column name $column
4832 if($debug) echo "preg_column_definition=(".$preg_column_definiton.")<hr />";
4833 $preg_columns_before = // columns before the one changed/dropped (keep)
4834 "(?:".
4835 "(". // group $2. Keep this one unchanged!
4836 "(?:".
4837 "$preg_column_definiton,\s*+". // column definition + comma
4838 ")*". // there might be any number of such columns here
4839 $preg_column_definiton. // last column definition
4840 ")". // end of group $2
4841 ",\s*+" // the last comma of the last column before the column to change. Do not keep it!
4842 .")?"; // there might be no columns before
4843 if($debug) echo "preg_columns_before=(".$preg_columns_before.")<hr />";
4844 $preg_columns_after = "(,\s*(.+))?"; // the columns after the column to drop. This is group $3 (drop) or $4(change) (keep!)
4845 // we could remove the comma using $6 instead of $5, but then we might have no comma at all.
4846 // Keeping it leaves a problem if we drop the first column, so we fix that case in another regex.
4847 $table_new = $table;
4848
4849 switch($action)
4850 {
4851 case 'add':
4852 if($column=='')
4853 {
4854 $this->alterError = $errormsg . ' (add) - '. $lang['alter_no_add_col'];
4855 return false;
4856 }
4857 $new_col_definition = "'$column_escaped' ".(isset($matches[5])?$matches[5]:'');
4858 $preg_pattern_add = "/^".$preg_create_table. // the CREATE TABLE statement ($1)
4859 "((?:(?!,\s*(?:PRIMARY\s+KEY\s*\(|CONSTRAINT\s|UNIQUE\s*\(|CHECK\s*\(|FOREIGN\s+KEY\s*\()).)*)". // column definitions ($2)
4860 "(.*)\\)\s*$/si"; // table-constraints like PRIMARY KEY(a,b) ($3) and the closing bracket
4861 // append the column definiton in the CREATE TABLE statement
4862 $newSQL = preg_replace($preg_pattern_add, '$1$2, '.strtr($new_col_definition, array('\\' => '\\\\', '$' => '\$')).' $3', $createtesttableSQL).')';
4863 $preg_error = $this->getPregError();
4864 if($debug)
4865 {
4866 echo $createtesttableSQL."<hr>";
4867 echo $newSQL."<hr>";
4868 echo $preg_pattern_add."<hr>";
4869 }
4870 if($newSQL==$createtesttableSQL) // pattern did not match, so column adding did not succed
4871 {
4872 $this->alterError = $errormsg . ' (add) - '.$lang['alter_pattern_mismatch'].'. PREG ERROR: '.$preg_error;
4873 return false;
4874 }
4875 $createtesttableSQL = $newSQL;
4876 break;
4877 case 'change':
4878 if(!isset($matches[6]) || !isset($matches[7]))
4879 {
4880 $this->alterError = $errormsg . ' (change) - '.$lang['alter_col_not_recognized'];
4881 return false;
4882 }
4883 $new_col_name = $matches[6];
4884 $new_col_type = $matches[7];
4885 $new_col_definition = "'$new_col_name' $new_col_type";
4886 $preg_column_to_change = "\s*".$this->sqlite_surroundings_preg($column)."(?:\s+".preg_quote($coltypes[$column]).")?(\s+(?:".$this->sqlite_surroundings_preg("*",false,",'\"`\[").")+)?";
4887 // replace this part (we want to change this column)
4888 // group $3 contains the column constraints (keep!). the name & data type is replaced.
4889 $preg_pattern_change = "/^".$preg_create_table.$preg_columns_before.$preg_column_to_change.$preg_columns_after."\s*\\)\s*$/s";
4890
4891 // replace the column definiton in the CREATE TABLE statement
4892 $newSQL = preg_replace($preg_pattern_change, '$1$2,'.strtr($new_col_definition, array('\\' => '\\\\', '$' => '\$')).'$3$4)', $createtesttableSQL);
4893 $preg_error = $this->getPregError();
4894 // remove comma at the beginning if the first column is changed
4895 // probably somebody is able to put this into the first regex (using lookahead probably).
4896 $newSQL = preg_replace("/^\s*(CREATE\s+TEMPORARY\s+TABLE\s+".preg_quote($this->quote($tmpname),"/")."\s+\(),\s*/",'$1',$newSQL);
4897 if($debug)
4898 {
4899 echo "preg_column_to_change=(".$preg_column_to_change.")<hr />";
4900 echo $createtesttableSQL."<hr />";
4901 echo $newSQL."<hr />";
4902
4903 echo $preg_pattern_change."<hr />";
4904 }
4905 if($newSQL==$createtesttableSQL || $newSQL=="") // pattern did not match, so column removal did not succed
4906 {
4907 $this->alterError = $errormsg . ' (change) - '.$lang['alter_pattern_mismatch'].'. PREG ERROR: '.$preg_error;
4908 return false;
4909 }
4910 $createtesttableSQL = $newSQL;
4911 $newcols[$column] = str_replace("''","'",$new_col_name);
4912 break;
4913 case 'drop':
4914 $preg_column_to_drop = "\s*".$this->sqlite_surroundings_preg($column)."\s+(?:".$this->sqlite_surroundings_preg("*",false,",'\"\[`").")+"; // delete this part (we want to drop this column)
4915 $preg_pattern_drop = "/^".$preg_create_table.$preg_columns_before.$preg_column_to_drop.$preg_columns_after."\s*\\)\s*$/s";
4916
4917 // remove the column out of the CREATE TABLE statement
4918 $newSQL = preg_replace($preg_pattern_drop, '$1$2$3)', $createtesttableSQL);
4919 $preg_error = $this->getPregError();
4920 // remove comma at the beginning if the first column is removed
4921 // probably somebody is able to put this into the first regex (using lookahead probably).
4922 $newSQL = preg_replace("/^\s*(CREATE\s+TEMPORARY\s+TABLE\s+".preg_quote($this->quote($tmpname),"/")."\s+\(),\s*/",'$1',$newSQL);
4923 if($debug)
4924 {
4925 echo $createtesttableSQL."<hr>";
4926 echo $newSQL."<hr>";
4927 echo $preg_pattern_drop."<hr>";
4928 }
4929 if($newSQL==$createtesttableSQL || $newSQL=="") // pattern did not match, so column removal did not succed
4930 {
4931 $this->alterError = $errormsg . ' (drop) - '.$lang['alter_pattern_mismatch'].'. PREG ERROR: '.$preg_error;
4932 return false;
4933 }
4934 $createtesttableSQL = $newSQL;
4935 unset($newcols[$column]);
4936 break;
4937 case 'rename to':
4938 // don't change column definition at all
4939 $newSQL = $createtesttableSQL;
4940 // only change the name of the table
4941 $table_new = $column;
4942 break;
4943 case 'add primary key':
4944 // we want to add a primary key for the column(s) stored in $column
4945 $newSQL = preg_replace("/\)\s*$/", ", PRIMARY KEY (".$column.") )", $createtesttableSQL);
4946 $createtesttableSQL = $newSQL;
4947 break;
4948 case 'drop primary key':
4949 // we want to drop the primary key
4950 if($debug) echo "DROP";
4951 if(sizeof($primarykey)==1)
4952 {
4953 // if not compound primary key, might be a column constraint -> try removal
4954 $column = $primarykey[0];
4955 if($debug) echo "<br>Trying to drop column constraint for column $column <br>";
4956 /*
4957 TODO: This does not work yet:
4958 CREATE TABLE 't12' ('t1' INTEGER CONSTRAINT "bla" NOT NULL CONSTRAINT 'pk' PRIMARY KEY ); ALTER TABLE "t12" DROP PRIMARY KEY
4959 This does: ! !
4960 CREATE TABLE 't12' ('t1' INTEGER CONSTRAINT bla NOT NULL CONSTRAINT 'pk' PRIMARY KEY ); ALTER TABLE "t12" DROP PRIMARY KEY
4961 */
4962 $preg_column_to_change = "(\s*".$this->sqlite_surroundings_preg($column).")". // column ($3)
4963 "(?:". // opt. type and column constraints
4964 "(\s+(?:".$this->sqlite_surroundings_preg("(?:[^PC,'\"`\[]|P(?!RIMARY\s+KEY)|".
4965 "C(?!ONSTRAINT\s+".$this->sqlite_surroundings_preg("+",false," ,'\"\[`")."\s+PRIMARY\s+KEY))",false,",'\"`\[").")*)". // column constraints before PRIMARY KEY ($3)
4966 // primary key constraint (remove this!):
4967 "(?:CONSTRAINT\s+".$this->sqlite_surroundings_preg("+",false," ,'\"\[`")."\s+)?".
4968 "PRIMARY\s+KEY".
4969 "(?:\s+(?:ASC|DESC))?".
4970 "(?:\s+ON\s+CONFLICT\s+(?:ROLLBACK|ABORT|FAIL|IGNORE|REPLACE))?".
4971 "(?:\s+AUTOINCREMENT)?".
4972 "((?:".$this->sqlite_surroundings_preg("*",false,",'\"`\[").")*)". // column constraints after PRIMARY KEY ($4)
4973 ")";
4974 // replace this part (we want to change this column)
4975 // group $3 (column) $4 (constraints before) and $5 (constraints after) contain the part to keep
4976 $preg_pattern_change = "/^".$preg_create_table.$preg_columns_before.$preg_column_to_change.$preg_columns_after."\s*\\)\s*$/si";
4977
4978 // replace the column definiton in the CREATE TABLE statement
4979 $newSQL = preg_replace($preg_pattern_change, '$1$2,$3$4$5$6)', $createtesttableSQL);
4980 // remove comma at the beginning if the first column is changed
4981 // probably somebody is able to put this into the first regex (using lookahead probably).
4982 $newSQL = preg_replace("/^\s*(CREATE\s+TEMPORARY\s+TABLE\s+".preg_quote($this->quote($tmpname),"/")."\s+\(),\s*/",'$1',$newSQL);
4983 if($debug)
4984 {
4985 echo "preg_column_to_change=(".$preg_column_to_change.")<hr />";
4986 echo $createtesttableSQL."<hr />";
4987 echo $newSQL."<hr />";
4988
4989 echo $preg_pattern_change."<hr />";
4990 }
4991 if($newSQL!=$createtesttableSQL && $newSQL!="") // pattern did match, so PRIMARY KEY constraint removed :)
4992 {
4993 $createtesttableSQL = $newSQL;
4994 if($debug) echo "<br>SUCCEEDED<br>";
4995 }
4996 else
4997 {
4998 if($debug) echo "NO LUCK";
4999 // TODO: try removing table constraint
5000 return false;
5001 }
5002 $createtesttableSQL = $newSQL;
5003 } else
5004 // TODO: Try removing table constraint
5005 return false;
5006
5007 break;
5008 default:
5009 if($debug) echo 'ERROR: unknown alter operation!<hr />';
5010 $this->alterError = $errormsg . $lang['alter_unknown_operation'];
5011 return false;
5012 }
5013 }
5014 $droptempsql = 'DROP TABLE '.$this->quote_id($tmpname);
5015
5016 $createnewtableSQL = "CREATE TABLE ".$this->quote($table_new)." ".preg_replace("/^\s*CREATE\s+TEMPORARY\s+TABLE\s+'?".str_replace("'","''",preg_quote($tmpname,"/"))."'?\s+(.*)$/is", '$1', $createtesttableSQL, 1);
5017
5018 $newcolumns = '';
5019 $oldcolumns = '';
5020 reset($newcols);
5021 while(list($key,$val) = each($newcols))
5022 {
5023 $newcolumns .= ($newcolumns?', ':'').$this->quote_id($val);
5024 $oldcolumns .= ($oldcolumns?', ':'').$this->quote_id($key);
5025 }
5026 $copytonewsql = 'INSERT INTO '.$this->quote_id($table_new).'('.$newcolumns.') SELECT '.$oldcolumns.' FROM '.$this->quote_id($tmpname);
5027 }
5028 }
5029 $alter_transaction = 'BEGIN; ';
5030 $alter_transaction .= $createtemptableSQL.'; '; //create temp table
5031 $alter_transaction .= $copytotempsql.'; '; //copy to table
5032 $alter_transaction .= $dropoldsql.'; '; //drop old table
5033 $alter_transaction .= $createnewtableSQL.'; '; //recreate original table
5034 $alter_transaction .= $copytonewsql.'; '; //copy back to original table
5035 $alter_transaction .= $droptempsql.'; '; //drop temp table
5036
5037 $preg_index="/^\s*(CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?:".$this->sqlite_surroundings_preg("+",false," '\"\[`")."\s*)*ON\s+)(".$this->sqlite_surroundings_preg($table).")(\s*\((?:".$this->sqlite_surroundings_preg("+",false," '\"\[`")."\s*)*\)\s*)\s*$/i";
5038 foreach($recreateQueries as $recreate_query)
5039 {
5040 if($recreate_query['type']=='index')
5041 {
5042 // this is an index. We need to make sure the index is not on a column that we drop. If it is, we drop the index as well.
5043 $indexInfos = $this->selectArray('PRAGMA index_info('.$this->quote_id($recreate_query['name']).')');
5044 foreach($indexInfos as $indexInfo)
5045 {
5046 if(!isset($newcols[$indexInfo['name']]))
5047 {
5048 if($debug) echo 'Not recreating the following index: <hr />'.htmlencode($recreate_query['sql']).'<hr />';
5049 // Index on a column that was dropped. Skip recreation.
5050 continue 2;
5051 }
5052 }
5053 }
5054 // TODO: In case we renamed a column on which there is an index, we need to recreate the index with the column name adjusted.
5055
5056 // recreate triggers / indexes
5057 if($table == $table_new)
5058 {
5059 // we had no RENAME TO, so we can recreate indexes/triggers just like the original ones
5060 $alter_transaction .= $recreate_query['sql'].';';
5061 } else
5062 {
5063 // we had a RENAME TO, so we need to exchange the table-name in the CREATE-SQL of triggers & indexes
5064 switch ($recreate_query['type'])
5065 {
5066 case 'index':
5067 $recreate_queryIndex = preg_replace($preg_index, '$1'.$this->quote_id(strtr($table_new, array('\\' => '\\\\', '$' => '\$'))).'$3 ', $recreate_query['sql']);
5068 if($recreate_queryIndex!=$recreate_query['sql'] && $recreate_queryIndex != NULL)
5069 $alter_transaction .= $recreate_queryIndex.';';
5070 else
5071 {
5072 // the CREATE INDEX regex did not match. this normally should not happen
5073 if($debug) echo 'ERROR: CREATE INDEX regex did not match!?<hr />';
5074 // just try to recreate the index originally (will fail most likely)
5075 $alter_transaction .= $recreate_query['sql'].';';
5076 }
5077 break;
5078
5079 case 'trigger':
5080 // TODO: IMPLEMENT
5081 $alter_transaction .= $recreate_query['sql'].';';
5082 break;
5083 default:
5084 if($debug) echo 'ERROR: Unknown type '.htmlencode($recreate_query['type']).'<hr />';
5085 $alter_transaction .= $recreate_query['sql'].';';
5086 }
5087 }
5088 }
5089 $alter_transaction .= 'COMMIT;';
5090 if($debug) echo $alter_transaction;
5091 return $this->multiQuery($alter_transaction);
5092 }
5093 }
5094
5095 //multiple query execution
5096 //returns true on success, false otherwise. Use getError() to fetch the error.
5097 public function multiQuery($query)
5098 {
5099 if($this->type=="PDO")
5100 $success = $this->db->exec($query);
5101 else if($this->type=="SQLite3")
5102 $success = $this->db->exec($query);
5103 else
5104 $success = $this->db->queryExec($query, $error);
5105 return $success;
5106 }
5107
5108
5109 // checks whether a table has a primary key
5110 public function hasPrimaryKey($table)
5111 {
5112 $query = "PRAGMA table_info(".$this->quote_id($table).")";
5113 $table_info = $this->selectArray($query);
5114 foreach($table_info as $row_id => $row_data)
5115 {
5116 if($row_data['pk'])
5117 {
5118 return true;
5119 }
5120
5121 }
5122 return false;
5123 }
5124
5125 // Returns an array of columns by which rows can be uniquely adressed.
5126 // For tables with a rowid column, this is always array('rowid')
5127 // for tables without rowid, this is an array of the primary key columns.
5128 public function getPrimaryKey($table)
5129 {
5130 $primary_key = array();
5131 // check if this table has a rowid
5132 $getRowID = $this->select('SELECT ROWID FROM '.$this->quote_id($table).' LIMIT 0,1');
5133 if(isset($getRowID[0]))
5134 // it has, so we prefer addressing rows by rowid
5135 return array('rowid');
5136 else
5137 {
5138 // the table is without rowid, so use the primary key
5139 $query = "PRAGMA table_info(".$this->quote_id($table).")";
5140 $table_info = $this->selectArray($query);
5141 foreach($table_info as $row_id => $row_data)
5142 {
5143 if($row_data['pk'])
5144 $primary_key[] = $row_data['name'];
5145 }
5146 }
5147 return $primary_key;
5148 }
5149
5150 // selects a row by a given key $pk, which is an array of values
5151 // for the columns by which a row can be adressed (rowid or primary key)
5152 public function wherePK($table, $pk)
5153 {
5154 $where = "";
5155 $primary_key = $this->getPrimaryKey($table);
5156 foreach($primary_key as $pk_index => $column)
5157 {
5158 if($where!="")
5159 $where .= " AND ";
5160 $where .= $this->quote_id($column) . ' = ';
5161 if(is_int($pk[$pk_index]) || is_float($pk[$pk_index]))
5162 $where .= $pk[$pk_index];
5163 else
5164 $where .= $this->quote($pk[$pk_index]);
5165 }
5166 return $where;
5167 }
5168
5169 //get number of rows in table
5170 public function numRows($table, $dontTakeLong = false)
5171 {
5172 // as Count(*) can be slow on huge tables without PK,
5173 // if $dontTakeLong is set and the size is > 2MB only count() if there is a PK
5174 if(!$dontTakeLong || $this->getSize() <= 2000 || $this->hasPrimaryKey($table))
5175 {
5176 $result = $this->select("SELECT Count(*) FROM ".$this->quote_id($table));
5177 return $result[0];
5178 } else
5179 {
5180 return '?';
5181 }
5182 }
5183
5184 //correctly escape a string to be injected into an SQL query
5185 public function quote($value)
5186 {
5187 if($this->type=="PDO")
5188 {
5189 // PDO quote() escapes and adds quotes
5190 return $this->db->quote($value);
5191 }
5192 else if($this->type=="SQLite3")
5193 {
5194 return "'".$this->db->escapeString($value)."'";
5195 }
5196 else
5197 {
5198 return "'".sqlite_escape_string($value)."'";
5199 }
5200 }
5201
5202 //correctly escape an identifier (column / table / trigger / index name) to be injected into an SQL query
5203 public function quote_id($value)
5204 {
5205 // double-quotes need to be escaped by doubling them
5206 $value = str_replace('"','""',$value);
5207 return '"'.$value.'"';
5208 }
5209
5210
5211 //import sql
5212 //returns true on success, error message otherwise
5213 public function import_sql($query)
5214 {
5215 $import = $this->multiQuery($query);
5216 if(!$import)
5217 return $this->getError();
5218 else
5219 return true;
5220 }
5221
5222 //import csv
5223 //returns true on success, error message otherwise
5224 public function import_csv($filename, $table, $field_terminate, $field_enclosed, $field_escaped, $null, $fields_in_first_row)
5225 {
5226 // CSV import implemented by Christopher Kramer - http://www.christosoft.de
5227 $csv_handle = fopen($filename,'r');
5228 $csv_insert = "BEGIN;\n";
5229 $csv_number_of_rows = 0;
5230 // PHP requires enclosure defined, but has no problem if it was not used
5231 if($field_enclosed=="") $field_enclosed='"';
5232 // PHP requires escaper defined
5233 if($field_escaped=="") $field_escaped='\\';
5234 while(!feof($csv_handle))
5235 {
5236 $csv_data = fgetcsv($csv_handle, 0, $field_terminate, $field_enclosed, $field_escaped);
5237 if($csv_data[0] != NULL || count($csv_data)>1)
5238 {
5239 $csv_number_of_rows++;
5240 if($fields_in_first_row && $csv_number_of_rows==1)
5241 {
5242 $fields_in_first_row = false;
5243 continue;
5244 }
5245 $csv_col_number = count($csv_data);
5246 $csv_insert .= "INSERT INTO ".$this->quote_id($table)." VALUES (";
5247 foreach($csv_data as $csv_col => $csv_cell)
5248 {
5249 if($csv_cell == $null) $csv_insert .= "NULL";
5250 else
5251 {
5252 $csv_insert.= $this->quote($csv_cell);
5253 }
5254 if($csv_col == $csv_col_number-2 && $csv_data[$csv_col+1]=='')
5255 {
5256 // the CSV row ends with the separator (like old phpliteadmin exported)
5257 break;
5258 }
5259 if($csv_col < $csv_col_number-1) $csv_insert .= ",";
5260 }
5261 $csv_insert .= ");\n";
5262
5263 if($csv_number_of_rows > 5000)
5264 {
5265 $csv_insert .= "COMMIT;\nBEGIN;\n";
5266 $csv_number_of_rows = 0;
5267 }
5268 }
5269 }
5270 $csv_insert .= "COMMIT;";
5271 fclose($csv_handle);
5272 $import = $this->multiQuery($csv_insert);
5273 if(!$import)
5274 return $this->getError();
5275 else
5276 return true;
5277 }
5278
5279 //export csv
5280 public function export_csv($tables, $field_terminate, $field_enclosed, $field_escaped, $null, $crlf, $fields_in_first_row)
5281 {
5282 $field_enclosed = $field_enclosed;
5283 $query = "SELECT * FROM sqlite_master WHERE type='table' or type='view' ORDER BY type DESC";
5284 $result = $this->selectArray($query);
5285 for($i=0; $i<sizeof($result); $i++)
5286 {
5287 $valid = false;
5288 for($j=0; $j<sizeof($tables); $j++)
5289 {
5290 if($result[$i]['tbl_name']==$tables[$j])
5291 $valid = true;
5292 }
5293 if($valid)
5294 {
5295 $query = "PRAGMA table_info(".$this->quote_id($result[$i]['tbl_name']).")";
5296 $temp = $this->selectArray($query);
5297 $cols = array();
5298 for($z=0; $z<sizeof($temp); $z++)
5299 $cols[$z] = $temp[$z][1];
5300 if($fields_in_first_row)
5301 {
5302 for($z=0; $z<sizeof($cols); $z++)
5303 {
5304 echo $field_enclosed.$cols[$z].$field_enclosed;
5305 // do not terminate the last column!
5306 if($z < sizeof($cols)-1)
5307 echo $field_terminate;
5308 }
5309 echo "\r\n";
5310 }
5311 $query = "SELECT * FROM ".$this->quote_id($result[$i]['tbl_name']);
5312 $arr = $this->selectArray($query, "assoc");
5313 for($z=0; $z<sizeof($arr); $z++)
5314 {
5315 for($y=0; $y<sizeof($cols); $y++)
5316 {
5317 $cell = $arr[$z][$cols[$y]];
5318 if($crlf)
5319 {
5320 $cell = str_replace("\n","", $cell);
5321 $cell = str_replace("\r","", $cell);
5322 }
5323 $cell = str_replace($field_terminate,$field_escaped.$field_terminate,$cell);
5324 $cell = str_replace($field_enclosed,$field_escaped.$field_enclosed,$cell);
5325 // do not enclose NULLs
5326 if($cell == NULL)
5327 echo $null;
5328 else
5329 echo $field_enclosed.$cell.$field_enclosed;
5330 // do not terminate the last column!
5331 if($y < sizeof($cols)-1)
5332 echo $field_terminate;
5333 }
5334 if($z<sizeof($arr)-1)
5335 echo "\r\n";
5336 }
5337 if($i<sizeof($result)-1)
5338 echo "\r\n";
5339 }
5340 }
5341 }
5342
5343 //export sql
5344 public function export_sql($tables, $drop, $structure, $data, $transaction, $comments)
5345 {
5346 global $lang;
5347 if($comments)
5348 {
5349 echo "----\r\n";
5350 echo "-- ".PROJECT." ".$lang['db_dump']." (".PROJECT_URL.")\r\n";
5351 echo "-- ".PROJECT." ".$lang['ver'].": ".VERSION."\r\n";
5352 echo "-- ".$lang['exported'].": ".date($lang['date_format'])."\r\n";
5353 echo "-- ".$lang['db_f'].": ".$this->getPath()."\r\n";
5354 echo "----\r\n";
5355 }
5356 $query = "SELECT * FROM sqlite_master WHERE type='table' OR type='index' OR type='view' OR type='trigger' ORDER BY type='trigger', type='index', type='view', type='table'";
5357 $result = $this->selectArray($query);
5358
5359 if($transaction)
5360 echo "BEGIN TRANSACTION;\r\n";
5361
5362 //iterate through each table
5363 for($i=0; $i<sizeof($result); $i++)
5364 {
5365 $valid = false;
5366 for($j=0; $j<sizeof($tables); $j++)
5367 {
5368 if($result[$i]['tbl_name']==$tables[$j])
5369 $valid = true;
5370 }
5371 if($valid)
5372 {
5373 if($drop)
5374 {
5375 if($comments)
5376 {
5377 echo "\r\n----\r\n";
5378 echo "-- ".$lang['drop']." ".$result[$i]['type']." ".$lang['for']." ".$result[$i]['name']."\r\n";
5379 echo "----\r\n";
5380 }
5381 echo "DROP ".strtoupper($result[$i]['type'])." ".$this->quote_id($result[$i]['name']).";\r\n";
5382 }
5383 if($structure)
5384 {
5385 if($comments)
5386 {
5387 echo "\r\n----\r\n";
5388 if($result[$i]['type']=="table" || $result[$i]['type']=="view")
5389 echo "-- ".ucfirst($result[$i]['type'])." ".$lang['struct_for']." ".$result[$i]['tbl_name']."\r\n";
5390 else // index or trigger
5391 echo "-- ".$lang['struct_for']." ".$result[$i]['type']." ".$result[$i]['name']." ".$lang['on_tbl']." ".$result[$i]['tbl_name']."\r\n";
5392 echo "----\r\n";
5393 }
5394 echo $result[$i]['sql'].";\r\n";
5395 }
5396 if($data && $result[$i]['type']=="table")
5397 {
5398 $query = "SELECT * FROM ".$this->quote_id($result[$i]['tbl_name']);
5399 $arr = $this->selectArray($query, "assoc");
5400
5401 if($comments)
5402 {
5403 echo "\r\n----\r\n";
5404 echo "-- ".$lang['data_dump']." ".$result[$i]['tbl_name'].", ".sprintf($lang['total_rows'], sizeof($arr))."\r\n";
5405 echo "----\r\n";
5406 }
5407 $query = "PRAGMA table_info(".$this->quote_id($result[$i]['tbl_name']).")";
5408 $temp = $this->selectArray($query);
5409 $cols = array();
5410 $cols_quoted = array();
5411 $vals = array();
5412 for($z=0; $z<sizeof($temp); $z++)
5413 {
5414 $cols[$z] = $temp[$z][1];
5415 $cols_quoted[$z] = $this->quote_id($temp[$z][1]);
5416 }
5417 for($z=0; $z<sizeof($arr); $z++)
5418 {
5419 for($y=0; $y<sizeof($cols); $y++)
5420 {
5421 if(!isset($vals[$z]))
5422 $vals[$z] = array();
5423 if($arr[$z][$cols[$y]] === NULL)
5424 $vals[$z][$cols[$y]] = 'NULL';
5425 else
5426 $vals[$z][$cols[$y]] = $this->quote_id($arr[$z][$cols[$y]]);
5427 }
5428 }
5429 for($j=0; $j<sizeof($vals); $j++)
5430 echo "INSERT INTO ".$this->quote_id($result[$i]['tbl_name'])." (".implode(",", $cols_quoted).") VALUES (".implode(",", $vals[$j]).");\r\n";
5431 }
5432 }
5433 }
5434 if($transaction)
5435 echo "COMMIT;\r\n";
5436 }
5437}
5438// class MicroTimer (issue #146)
5439// wraps calls to microtime(), calculating the elapsed time and rounding output
5440//
5441class MicroTimer {
5442
5443 private $startTime, $stopTime;
5444
5445 // creates and starts a timer
5446 function __construct()
5447 {
5448 $this->startTime = microtime(true);
5449 }
5450
5451 // stops a timer
5452 public function stop()
5453 {
5454 $this->stopTime = microtime(true);
5455 }
5456
5457 // returns the number of seconds from the timer's creation, or elapsed
5458 // between creation and call to ->stop()
5459 public function elapsed()
5460 {
5461 if ($this->stopTime)
5462 return round($this->stopTime - $this->startTime, 4);
5463
5464 return round(microtime(true) - $this->startTime, 4);
5465 }
5466
5467 // called when using a MicroTimer object as a string
5468 public function __toString()
5469 {
5470 return (string) $this->elapsed();
5471 }
5472
5473}
5474// class Resources (issue #157)
5475// outputs secondary files, such as css and javascript
5476// data is stored gzipped (gzencode) and encoded (base64_encode)
5477//
5478class Resources {
5479
5480 // set this to the file containing getInternalResource;
5481 // currently unused in split mode; set to __FILE__ for built PLA.
5482 public static $embedding_file = __FILE__;
5483
5484 private static $_resources = array(
5485 'css' => array(
5486 'mime' => 'text/css',
5487 'data' => 'resources/phpliteadmin.css',
5488 ),
5489 'javascript' => array(
5490 'mime' => 'text/javascript',
5491 'data' => 'resources/phpliteadmin.js',
5492 ),
5493 'favicon' => array(
5494 'mime' => 'image/x-icon',
5495 'data' => 'resources/favicon.ico',
5496 'base64' => 'true',
5497 ),
5498 );
5499
5500 // outputs the specified resource, if defined in this class.
5501 // the main script should do no further output after calling this function.
5502 public static function output($resource)
5503 {
5504 if (isset(self::$_resources[$resource])) {
5505 $res =& self::$_resources[$resource];
5506
5507 if (function_exists('getInternalResource') && $data = getInternalResource($res['data'])) {
5508 $filename = self::$embedding_file;
5509 } else {
5510 $filename = $res['data'];
5511 }
5512
5513 // use last-modified time as etag; etag must be quoted
5514 $etag = '"' . filemtime($filename) . '"';
5515
5516 // check headers for matching etag; if etag hasn't changed, use the cached version
5517 if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == $etag) {
5518 header('HTTP/1.0 304 Not Modified');
5519 return;
5520 }
5521
5522 header('Etag: ' . $etag);
5523
5524 // cache file for at most 30 days
5525 header('Cache-control: max-age=2592000');
5526
5527 // output resource
5528 header('Content-type: ' . $res['mime']);
5529
5530 if (isset($data)) {
5531 if (isset($res['base64'])) {
5532 echo base64_decode($data);
5533 } else {
5534 echo $data;
5535 }
5536 } else {
5537 readfile($filename);
5538 }
5539 }
5540 }
5541
5542}
5543
5544
5545// returns data from internal resources, available in single-file mode
5546function getInternalResource($res) {
5547 $resources = array('resources/phpliteadmin.css'=>array(0=>0,1=>3954,),'resources/phpliteadmin.js'=>array(0=>3954,1=>4178,),'resources/favicon.ico'=>array(0=>8132,1=>1448,),);
5548
5549 if (isset($resources[$res]) && $f = fopen(__FILE__, 'r')) {
5550 fseek($f, __COMPILER_HALT_OFFSET__ + $resources[$res][0]);
5551 $data = fread($f, $resources[$res][1]);
5552 fclose($f);
5553 return $data;
5554 }
5555 return false;
5556}
5557
5558// resources embedded below, do not edit!
5559__halt_compiler() ?>body{margin:0px;padding:0px;font-family:Arial,Helvetica,sans-serif;font-size:14px;color:#000;background-color:#e0ebf6;overflow:auto}.body_tbl td{padding:9px 2px 9px 9px}.left_td{width:100px}a{color:#03F;text-decoration:none;cursor:pointer}a:hover{color:#06F}hr{height:1px;border:0;color:#bbb;background-color:#bbb;width:100%}h1{margin:0px;padding:5px;font-size:24px;background-color:#f3cece;text-align:center;color:#000;border-top-left-radius:5px;border-top-right-radius:5px;-moz-border-radius-topleft:5px;-moz-border-radius-topright:5px}#headerlinks{text-align:center;margin-bottom:10px;padding:5px 15px;border-color:#03F;border-width:1px;border-style:solid;border-left-style:none;border-right-style:none;font-size:12px;background-color:#e0ebf6;font-weight:bold}h1 #version{color:#000;font-size:16px}h1 #logo{color:#000}h2{margin:0px;padding:0px;font-size:14px;margin-bottom:20px}input,select,textarea{font-family:Arial,Helvetica,sans-serif;background-color:#eaeaea;color:#03F;border-color:#03F;border-style:solid;border-width:1px;margin:5px;border-radius:5px;-moz-border-radius:5px;padding:3px}input.btn{cursor:pointer}input.btn:hover{background-color:#ccc}fieldset{padding:15px;border-color:#03F;border-width:1px;border-style:solid;border-radius:5px;-moz-border-radius:5px;background-color:#f9f9f9}#container{padding:10px}#leftNav{min-width:250px;padding:0px;border-color:#03F;border-width:1px;border-style:solid;background-color:#FFF;padding-bottom:15px;border-radius:5px;-moz-border-radius:5px}.viewTable tr td{padding:1px}#loginBox{width:500px;margin-left:auto;margin-right:auto;margin-top:50px;border-color:#03F;border-width:1px;border-style:solid;background-color:#FFF;border-radius:5px;-moz-border-radius:5px}#main{border-color:#03F;border-width:1px;border-style:solid;padding:15px;background-color:#FFF;border-bottom-left-radius:5px;border-bottom-right-radius:5px;border-top-right-radius:5px;-moz-border-radius-bottomleft:5px;-moz-border-radius-bottomright:5px;-moz-border-radius-topright:5px}.td1{background-color:#f9e3e3;text-align:right;font-size:12px;padding-left:10px;padding-right:10px}.td2{background-color:#f3cece;text-align:right;font-size:12px;padding-left:10px;padding-right:10px}.tdheader{border-color:#03F;border-width:1px;border-style:solid;font-weight:bold;font-size:12px;padding-left:10px;padding-right:10px;background-color:#e0ebf6;border-radius:5px;-moz-border-radius:5px}.confirm{border-color:#03F;border-width:1px;border-style:dashed;padding:15px;background-color:#e0ebf6}.tab{display:block;padding:5px;padding-right:8px;padding-left:8px;border-color:#03F;border-width:1px;border-style:solid;margin-right:5px;float:left;border-bottom-style:none;position:relative;top:1px;padding-bottom:4px;background-color:#eaeaea;border-top-left-radius:5px;border-top-right-radius:5px;-moz-border-radius-topleft:5px;-moz-border-radius-topright:5px}.tab_pressed{display:block;padding:5px;padding-right:8px;padding-left:8px;border-color:#03F;border-width:1px;border-style:solid;margin-right:5px;float:left;border-bottom-style:none;position:relative;top:1px;background-color:#FFF;cursor:default;border-top-left-radius:5px;border-top-right-radius:5px;-moz-border-radius-topleft:5px;-moz-border-radius-topright:5px}.helpq{font-size:11px;font-weight:normal}#help_container{padding:0px;font-size:12px;margin-left:auto;margin-right:auto;background-color:#fff}.help_outer{background-color:#FFF;padding:0px;height:300px;position:relative}.help_list{padding:10px;height:auto}.headd{font-size:14px;font-weight:bold;display:block;padding:10px;background-color:#e0ebf6;border-color:#03F;border-width:1px;border-style:solid;border-left-style:none;border-right-style:none}.help_inner{padding:10px}.help_top{display:block;position:absolute;right:10px;bottom:10px}.warning,.delete,.empty,.drop,.delete_db{color:red}.sidebar_table{font-size:11px}.active_table,.active_db{text-decoration:underline}.null{color:#888}.found{background:#FF0;text-decoration:none}
5560function initAutoincrement()
5561{var i=0;while(document.getElementById('i'+i+'_autoincrement')!=undefined)
5562{document.getElementById('i'+i+'_autoincrement').disabled=true;i++;}}
5563function toggleAutoincrement(i)
5564{var type=document.getElementById('i'+i+'_type');var primarykey=document.getElementById('i'+i+'_primarykey');var autoincrement=document.getElementById('i'+i+'_autoincrement');if(!autoincrement)return false;if(type.value=='INTEGER'&&primarykey.checked)
5565autoincrement.disabled=false;else
5566{autoincrement.disabled=true;autoincrement.checked=false;}}
5567function toggleNull(i)
5568{var pk=document.getElementById('i'+i+'_primarykey');var notnull=document.getElementById('i'+i+'_notnull');if(pk.checked)
5569{notnull.disabled=true;notnull.checked=true;}
5570else
5571{notnull.disabled=false;}}
5572function checkAll(field)
5573{var i=0;while(document.getElementById('check_'+i)!=undefined)
5574{document.getElementById('check_'+i).checked=true;i++;}}
5575function uncheckAll(field)
5576{var i=0;while(document.getElementById('check_'+i)!=undefined)
5577{document.getElementById('check_'+i).checked=false;i++;}}
5578function changeIgnore(area,e,u)
5579{if(area.value!="")
5580{if(document.getElementById(e)!=undefined)
5581document.getElementById(e).checked=false;if(document.getElementById(u)!=undefined)
5582document.getElementById(u).checked=false;}}
5583function moveFields()
5584{var fields=document.getElementById("fieldcontainer");var selected=new Array();for(var i=0;i<fields.options.length;i++)
5585if(fields.options[i].selected)
5586selected.push(fields.options[i].value);for(var i=0;i<selected.length;i++)
5587insertAtCaret("queryval",'"'+selected[i].replace(/"/g,'""')+'"');}
5588function insertAtCaret(areaId,text)
5589{var txtarea=document.getElementById(areaId);var scrollPos=txtarea.scrollTop;var strPos=0;var br=((txtarea.selectionStart||txtarea.selectionStart=='0')?"ff":(document.selection?"ie":false));if(br=="ie")
5590{txtarea.focus();var range=document.selection.createRange();range.moveStart('character',-txtarea.value.length);strPos=range.text.length;}
5591else if(br=="ff")
5592strPos=txtarea.selectionStart;var front=(txtarea.value).substring(0,strPos);var back=(txtarea.value).substring(strPos,txtarea.value.length);txtarea.value=front+text+back;strPos=strPos+text.length;if(br=="ie")
5593{txtarea.focus();var range=document.selection.createRange();range.moveStart('character',-txtarea.value.length);range.moveStart('character',strPos);range.moveEnd('character',0);range.select();}
5594else if(br=="ff")
5595{txtarea.selectionStart=strPos;txtarea.selectionEnd=strPos;txtarea.focus();}
5596txtarea.scrollTop=scrollPos;}
5597function notNull(checker)
5598{document.getElementById(checker).checked=false;}
5599function disableText(checker,textie)
5600{if(checker.checked)
5601{document.getElementById(textie).value="";document.getElementById(textie).disabled=true;}
5602else
5603{document.getElementById(textie).disabled=false;}}
5604function toggleExports(val)
5605{document.getElementById("exportoptions_sql").style.display="none";document.getElementById("exportoptions_csv").style.display="none";document.getElementById("exportoptions_"+val).style.display="block";}
5606function toggleImports(val)
5607{document.getElementById("importoptions_sql").style.display="none";document.getElementById("importoptions_csv").style.display="none";document.getElementById("importoptions_"+val).style.display="block";}
5608function openHelp(section)
5609{PopupCenter('?help=1#'+section,"Help Section");}
5610var helpsec=false;function PopupCenter(pageURL,title)
5611{helpsec=window.open(pageURL,title,"toolbar=0,scrollbars=1,location=0,statusbar=0,menubar=0,resizable=0,width=400,height=300");}
5612function checkLike(srchField,selOpt)
5613{if(selOpt=="LIKE%"){var textArea=document.getElementById(srchField);textArea.value="%"+textArea.value+"%";}}
5614function createCORSRequest(method,url)
5615{var xhr=new XMLHttpRequest();if("withCredentials"in xhr)
5616{xhr.open(method,url,true);}
5617else if(typeof XDomainRequest!="undefined")
5618{xhr=new XDomainRequest();xhr.open(method,url);}
5619else
5620{xhr=null;}
5621return xhr;}
5622function checkVersion(installed,url)
5623{var xhr=createCORSRequest('GET',url);if(!xhr)
5624return false;xhr.onload=function()
5625{if(xhr.responseText.split("\n").indexOf(installed)==-1)
5626{document.getElementById('oldVersion').style.display='inline';}};xhr.send();}AAABAAEAEBAAAAEAIAAoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwoKZQAAABMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEMDJMAAAAdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASDg7BAAAASAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAETDw9CCQkJ1QUFBb4AAABjAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgsLVgAAAO8YExP/AAAA7QAAALEAAAARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQNDUsAAADJGBMT/xgTE/8AAAD/AAAAuAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZERE8DQoKwhgTE/8QDQ2sGBMT/xgTE/8AAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwICHkAAAD/EQwMzQAAAMIAAAD/AAAA7gAAAGEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOCwtWAAAA8RgTE/8IBQW1AAAA/wAAAP8AAADlAAAAHQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0KCsEAAAD/EQ8PzAAAAMkAAAD/AAAA/wAAAHoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABDAAAA/xgTE/8TDw/FAAAA8gAAAP8AAADqAAAAJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAALUAAAD/GBMT/wAAALkAAAD/AAAA/wAAAIkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfAAAA4wAAAP8GBgbFAAAA2QAAAP8AAADGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF4AAAD5AAAA/RgTE/8AAAD/AAAA0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQQAAAOIAAAD/AAAA/wAAAHYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjAAAArgAAAG4AAAAAAAAAAAAAAAAAAAAA