├── .github ├── dependabot.yml └── workflows │ └── codeql.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── accessories.php ├── admin.php ├── assets └── css │ └── main.css ├── data.php ├── database.php ├── iframe_content.php ├── inc ├── DataForm.php ├── array_functions.inc.php ├── configuration.inc.php ├── debug_funcs.inc.php ├── display_variable.php ├── domains.inc.php ├── exceptions.inc.php ├── export.inc.php ├── firebird.inc.php ├── foreign_keys.inc.php ├── functions.inc.php ├── get_tables.inc.php ├── handle_editdata.inc.php ├── handle_watchtable.inc.php ├── indices.inc.php ├── javascript.inc.php ├── kill_session.php ├── panel_elements.inc.php ├── procedures.inc.php ├── roles.inc.php ├── script_end.inc.php ├── script_start.inc.php ├── session.inc.php ├── system_table.inc.php ├── triggers.inc.php ├── udfs.inc.php ├── users.inc.php ├── views.inc.php └── xml_http_request_server.php ├── index.html ├── js ├── XMLHttpRequestClient.js └── miscellaneous.js ├── lang ├── Czech.inc.php ├── Portuguese, Brazilian.inc.php ├── Romanian.inc.php ├── Russian.inc.php ├── check_languages.php ├── dutch.inc.php ├── english.inc.php ├── german.inc.php ├── hungarian.inc.php ├── japanese.inc.php ├── polish.inc.php └── spanish.inc.php ├── logout.php ├── package.json ├── panels ├── acc_domain.php ├── acc_exc.php ├── acc_gen.php ├── acc_index.php ├── acc_proc.php ├── acc_trigger.php ├── acc_udf.php ├── acc_view.php ├── adm_backup.php ├── adm_dbstat.php ├── adm_gfix.php ├── adm_restore.php ├── adm_server.php ├── confirm.php ├── db_create.php ├── db_delete.php ├── db_login.php ├── db_meta.php ├── db_systable.php ├── dt_edit.php ├── dt_enter.php ├── dt_export.php ├── dt_import.php ├── info.php ├── sql_enter.php ├── sql_output.php ├── tb_create.php ├── tb_delete.php ├── tb_dropfields.php ├── tb_droptables.php ├── tb_modify.php ├── tb_show.php ├── tb_showselectable.php ├── tb_watch.php ├── usr_role.php └── usr_user.php ├── settings.php ├── showblob.php ├── showimage.php ├── sql.php ├── tables.php ├── toggle_fold_panel.php ├── user.php ├── views ├── footer.php ├── header.php └── menu.php └── watchtable.php /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "master" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "master" ] 20 | schedule: 21 | - cron: '36 21 * * 0' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'javascript' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Use only 'java' to analyze code written in Java, Kotlin or both 38 | # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both 39 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 40 | 41 | steps: 42 | - name: Checkout repository 43 | uses: actions/checkout@v3 44 | 45 | # Initializes the CodeQL tools for scanning. 46 | - name: Initialize CodeQL 47 | uses: github/codeql-action/init@v2 48 | with: 49 | languages: ${{ matrix.language }} 50 | # If you wish to specify custom queries, you can do so here or in a config file. 51 | # By default, queries listed here will override any specified in a config file. 52 | # Prefix the list here with "+" to use these queries and those in the config file. 53 | 54 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 55 | # queries: security-extended,security-and-quality 56 | 57 | 58 | # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). 59 | # If this step fails, then you should remove it and run the build manually (see below) 60 | - name: Autobuild 61 | uses: github/codeql-action/autobuild@v2 62 | 63 | # ℹ️ Command-line programs to run using the OS shell. 64 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 65 | 66 | # If the Autobuild fails above, remove it and uncomment the following three lines. 67 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 68 | 69 | # - run: | 70 | # echo "Run, Build Application using script" 71 | # ./location_of_script_within_repo/buildscript.sh 72 | 73 | - name: Perform CodeQL Analysis 74 | uses: github/codeql-action/analyze@v2 75 | with: 76 | category: "/language:${{matrix.language}}" 77 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile '~/.gitignore_global' 6 | 7 | # PhpStorm 8 | .idea/**/* -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # ChangeLog 2 | 3 | ## Version 3.4.1 (27.02.2020) 4 | 5 | * [enhancement:] Adjust "Accessories" page UI. 6 | * [enhancement:] Remove Crowdin badge from footer. 7 | * [enhancement:] Update debug_funcs.inc.php 8 | * [bugfix:] Don't warn if "isql" is "isql-fb" on Linux 9 | * [typo:] Correct typo: firebirid -> firebird 10 | * [bugfix] fix sql create database 11 | * [enhancement:] Add Character Sets 12 | * [enhancement:] Quiet PHP7.2 deprecation warning … 13 | * [enhancement:] Further create_function refactor 14 | * [enhancement:] Remove unused/outdated markableFbwaTable. 15 | * [enhancement:] cosmetics 16 | 17 | ## Version 3.4.0 (27.11.2016) 18 | 19 | * [enhancement:] Published on npm 20 | * [enhancement:] Introduce CHANGELOG.md 21 | * [enhancement:] Rename README to README.md (alse updated structure, markdown, info badges) 22 | * [enhancement:] Update translations 23 | * [bugfix:] Update export.inc.php (.csv) 24 | * [bugfix:] Suffixes GDB etc should be off by default 25 | * [enhancement:] Review Exceptions & indices from Accessories. 26 | 27 | ## Version 3.3.0 (06.01.2016) 28 | 29 | * [enhancement:] Review User Page. Modal popup for Role creation. Delete role button for each role. 30 | * [enhancement:] Users: Remove "Customizing" panel. Is not database/server related. 31 | * [enhancement:] Initial integration with Crowdin. Convert all files to UTF-8. 32 | * [enhancement:] Update Romanian & Russian translations. 33 | * [enhancement:] UI improvements: Roles, Users, Exceptions, UDF, Table comments. 34 | * [enhancement:] Integration with CodeMirror. 35 | * [enhancement:] In-browser code editor 36 | 37 | ## Version 3.2.2 (24.11.2015) 38 | 39 | * [enhancement:] Remove unused php function related to icon paths 40 | 41 | ## Version 3.2.1 (24.11.2015) 42 | 43 | * [enhancement:] Mostly code cleanups : Remove unused js functions , Replace vanilla selectors with jquery selectors 44 | 45 | ## Version 3.2.0 (23.11.2015) 46 | 47 | * [enhancement:] Admin page UI improvements. 48 | 49 | ## Version 3.1.0 (11.11.2015) 50 | 51 | * [enhancement:] No info panel. Now is notification area with dismissible alerts. 52 | * [enhancement:] SQL page review. 53 | 54 | ## Version 3.0.2 (10.11.2015) 55 | 56 | * [enhancement:] Update bootstrap version and theme. 57 | * [enhancement:] Database & Tables page. UI improvements. Delete all images. 58 | * [enhancement:] Sticky footer with project github link, full version and debug info. 59 | * [enhancement:] Header user menu with connection string & Logout. 60 | 61 | ## Version 3.0.1 (06.11.2015) 62 | 63 | * [enhancement:] Improvements to UI , @dumitru replaced the png maximize/minimize icons with glyphicons 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FirebirdWebAdmin is a web frontend for the Firebird database server 2 | 3 | [![Crowdin](https://d322cqt584bo4o.cloudfront.net/firebirdwebadmin/localized.svg)](https://crowdin.com/project/firebirdwebadmin) 4 | [![Code Climate](https://codeclimate.com/github/mariuz/firebirdwebadmin/badges/gpa.svg)](https://codeclimate.com/github/mariuz/firebirdwebadmin) 5 | 6 | By now it has the functionalities for 7 | 8 | * creating, deleting, modifying databases, tables, generators, views, triggers, domains, indices, stored procedures, udf's, exceptions, roles and database users 9 | * performing sql expressions on databases and display the results 10 | * import and export of data through files in the csv format 11 | * browsing through the contents of tables and views, watching them growing while typing in data 12 | * selecting data for deleting and editing while browsing tables 13 | * inserting, deleting, displaying the contents of blob fields 14 | * diplaying database metadata, browsing the firebird system tables 15 | * database backup and restore, database maintenance 16 | 17 | Some of the features are only available if the database- and the web-server are running on the same machine. The reason is that php have to call the Firebird tools (isql, gsec, gstat, etc.) to perform certain actions. 18 | 19 | ## Overview 20 | 21 | 1. [Documentation](#documentation) 22 | 2. [Requirements](#requirements) 23 | 3. [ChangeLog](#requirements) 24 | 4. [Contributing](#contributing) 25 | 5. [Copyright notice](#copyright-notice) 26 | 27 | ## Documentation 28 | 29 | There is no documentation available yet, but if you are familiar with Firebird you will have no troubles using FirebirdWebAdmin. 30 | 31 | For some basic configuration settings have a look to the file `./inc/configuration.inc.php` before you start the programm. 32 | 33 | Here is how to use and install on Ubuntu 34 | 35 | Firebird documentation is located on this page 36 | 37 | ## Requirements 38 | 39 | This is the environment I'm using for the development. Other components are not or less tested. So if you got problems make sure you are not using older software components. 40 | 41 | PHP with compiled in support for Firebird/InterBase and pcre (but any version >= 5.5 should work) 42 | 43 | Firebird 2.x.x for Linux, 44 | Apache 2.x or any server with php support 45 | 46 | ## ChangeLog 47 | 48 | ### Version 3.4.1 (27.02.2020) 49 | 50 | * [enhancement:] Adjust "Accessories" page UI. 51 | * [enhancement:] Remove Crowdin badge from footer. 52 | * [enhancement:] Update debug_funcs.inc.php 53 | * [bugfix:] Don't warn if "isql" is "isql-fb" on Linux 54 | * [typo:] Correct typo: firebirid -> firebird 55 | * [bugfix] fix sql create database 56 | * [enhancement:] Add Character Sets 57 | * [enhancement:] Quiet PHP7.2 deprecation warning … 58 | * [enhancement:] Further create_function refactor 59 | * [enhancement:] Remove unused/outdated markableFbwaTable. 60 | * [enhancement:] cosmetics 61 | 62 | #### Further informations 63 | 64 | * See [CHANGELOG.md][changelog] to get the full changelog. 65 | 66 | ## Contributing 67 | 68 | 1. Fork it 69 | 2. Create your feature branch (`git checkout -b my-new-feature`) 70 | 3. Commit your changes (`git commit -am 'Add some feature'`) 71 | 4. Push to the branch (`git push origin my-new-feature`) 72 | 5. Create new Pull Request 73 | 74 | ## Copyright notice 75 | 76 | (C) 2000,2001,2002,2003,2004 Lutz Brueckner 77 | Kapellenstr. 1A 78 | 22117 Hamburg, Germany 79 | 80 | FirebirdWebAdmin is published under the terms of the [GNU GPL v.2][gnu_gpl_v2_license], please read the file LICENCE for details. 81 | 82 | This software is provided 'as-is', without any expressed or implied warranty. In no event will the author be held liable for any damages arising from the use of this software. 83 | 84 | [gnu_gpl_v2_license]: https://opensource.org/licenses/GPL-2.0 85 | [changelog]: CHANGELOG.md 86 | -------------------------------------------------------------------------------- /assets/css/main.css: -------------------------------------------------------------------------------- 1 | html { 2 | position: relative; 3 | min-height: 100%; 4 | } 5 | 6 | body { 7 | padding-top: 70px; 8 | } 9 | 10 | .margin-bottom-0px { 11 | margin-bottom: 0 12 | } 13 | 14 | .footer { 15 | position: absolute; 16 | bottom: 0; 17 | width: 100%; 18 | /* Set the fixed height of the footer here */ 19 | height: 60px; 20 | background-color: #f5f5f5; 21 | } 22 | 23 | .container { 24 | -width: auto; 25 | -max-width: 680px; 26 | -padding: 0 15px; 27 | } 28 | .container .text-muted { 29 | margin: 20px 0; 30 | } 31 | 32 | .margin-left-10px { 33 | margin-left: 10px !important; 34 | } 35 | 36 | .margin-left-20px { 37 | margin-left: 20px !important; 38 | } 39 | 40 | 41 | .CodeMirror { 42 | border-top: 1px solid gainsboro; 43 | border-right: 1px solid gainsboro; 44 | } -------------------------------------------------------------------------------- /iframe_content.php: -------------------------------------------------------------------------------- 1 | 5 | // Copyright (c) 2000-2006 by Lutz Brueckner, 6 | // published under the terms of the GNU General Public Licence v.2, 7 | // see file LICENCE for details 8 | 9 | // do not overwrite $s_referer in script_start.inc.php 10 | $no_session_referer = true; 11 | 12 | require './inc/script_start.inc.php'; 13 | 14 | $key = get_request_data('key', 'GET'); 15 | 16 | if ($job = get_iframejob($s_iframejobs, $key)) { 17 | switch ($job['job']) { 18 | case 'metadata': 19 | list($content, $error) = isql_get_metadata($s_login['user'], $s_login['password'], $s_login['database'], $s_login['host']); 20 | $content = implode("\n", $content); 21 | break; 22 | 23 | case 'dbstat': 24 | if (($service = fbird_service_attach($s_login['host'], $s_login['user'], $s_login['password'])) != false) { 25 | $content = fbird_db_info($service, $s_login['database'], $job['option']); 26 | $content = trim(str_replace(array(chr(0x01), "\n\n"), array('', "\n"), $content)); 27 | fbird_service_detach($service); 28 | } else { 29 | $error = fbird_errmsg(); 30 | } 31 | break; 32 | 33 | case 'backup': 34 | if (($service = fbird_service_attach($s_login['host'], $s_login['user'], $s_login['password'])) != false) { 35 | $content = fbird_backup($service, $job['source'], $job['target'], $job['options'], true); 36 | $content = str_replace(array(chr(0x01).chr(0x0a), 'gbak: '), '', $content); 37 | fbird_service_detach($service); 38 | } else { 39 | $error = fbird_errmsg(); 40 | } 41 | break; 42 | 43 | case 'restore': 44 | if (($service = fbird_service_attach($s_login['host'], $s_login['user'], $s_login['password'])) != false) { 45 | $content = fbird_restore($service, $job['source'], $job['target'], $job['options'], true); 46 | $content = str_replace(array(chr(0x01).chr(0x0a), 'gbak: '), '', $content); 47 | fbird_service_detach($service); 48 | 49 | // try to connect the restored database 50 | if ($job['connect']) { 51 | $s_login['database'] = $job['target']; 52 | if (!empty($s_sysdba_pw)) { 53 | $s_login['user'] = 'SYSDBA'; 54 | $s_login['password'] = $s_sysdba_pw; 55 | } 56 | 57 | if ($dbhandle = db_connect()) { 58 | // connected successfully 59 | $s_connected = true; 60 | remove_edit_panels(); 61 | } else { 62 | // connect failed 63 | $content .= '

'.$info_strings['FBError'].':'.fbird_errmsg()."

\n"; 64 | $s_login['password'] = ''; 65 | $s_connected = false; 66 | } 67 | cleanup_session(); 68 | } 69 | } else { 70 | $error = fbird_errmsg(); 71 | } 72 | break; 73 | 74 | case 'export': 75 | 76 | include './inc/export.inc.php'; 77 | 78 | ob_start(); 79 | export_data($job['data']); 80 | $content = ob_get_contents(); 81 | ob_end_clean(); 82 | break; 83 | } 84 | 85 | echo iframe_content($content, $error); 86 | 87 | unset($s_iframejobs[$key]); 88 | globalize_session_vars(); 89 | } 90 | 91 | function get_iframejob($iframejobs, $key) 92 | { 93 | if (isset($iframejobs[$key])) { 94 | return $iframejobs[$key]; 95 | } 96 | 97 | return false; 98 | } 99 | 100 | function iframe_content($content, $error) 101 | { 102 | return html_head('FirebirdWebAdmin '.VERSION) 103 | ."\n" 104 | .($error ? '

'.$GLOBALS['info_strings']['Error'].': '.$error."

\n" : '') 105 | ."
\n"
106 |          .htmlspecialchars($content)."\n"
107 |          ."
\n" 108 | ."\n" 109 | ."\n"; 110 | } 111 | -------------------------------------------------------------------------------- /inc/array_functions.inc.php: -------------------------------------------------------------------------------- 1 | 5 | // Copyright (c) 2000-2006 by Lutz Brueckner, 6 | // published under the terms of the GNU General Public Licence v.2, 7 | // see file LICENCE for details 8 | 9 | // 10 | // move the element from $pos to the top of the array, return the array 11 | // 12 | function array_moveto_top($arr, $pos) 13 | { 14 | $newarr[] = $arr[$pos]; 15 | for ($i = 0; $i < count($arr); ++$i) { 16 | if ($i != $pos) { 17 | $newarr[] = $arr[$i]; 18 | } 19 | } 20 | 21 | return $newarr; 22 | } 23 | 24 | // 25 | // determine the maximum index from an numeric indexed array 26 | // 27 | function get_max_key($arr) 28 | { 29 | end($arr); 30 | $key = key($arr); 31 | 32 | return $key; 33 | } 34 | -------------------------------------------------------------------------------- /inc/configuration.inc.php: -------------------------------------------------------------------------------- 1 | 5 | // Copyright (c) 2000-2006 by Lutz Brueckner, 6 | // published under the terms of the GNU General Public Licence v.2, 7 | // see file LICENCE for details 8 | 9 | 10 | // 11 | // For the defines of paths you have to use slashes, even in a windows environment! 12 | // i.e define('BINPATH', 'c:/firebird/bin/'); 13 | // 14 | 15 | define('VERSION', '3.4.1'); 16 | 17 | define('BINPATH', '/usr/sbin/'); // path to the interbase tools (isql, etc.) 18 | 19 | define('TMPPATH', '/tmp/'); // write temporary files here, 20 | // must be writeable for the webserver, must be an absolute path 21 | 22 | define('DEFAULT_USER', 'SYSDBA'); // default settings for database login 23 | define('DEFAULT_DB', 'employee.fdb'); 24 | define('DEFAULT_PATH', '/var/lib/firebird/2.5/data/'); 25 | define('DEFAULT_HOST', 'localhost'); 26 | define('DEFAULT_ROLE', ''); 27 | define('DEFAULT_CACHE', 75); 28 | define('DEFAULT_CHARSET', 'NONE'); 29 | define('DEFAULT_DIALECT', 3); 30 | define('DEFAULT_SERVER', 'FB_2.5'); // 'FB_2.1', 'FB_2.5' and 'other' are the valid options 31 | 32 | 33 | define('PROTOCOL', 'http'); // change to 'https' to use ssl 34 | 35 | // TODO: Review SP_LIMIT_NAME. Now is defined to avoid warnings. 36 | define('SP_LIMIT_NAME', ''); 37 | 38 | 39 | // if $ALLOWED_DIRS is not empty, only database in this directories are allowed to open; 40 | // the webserver process must have read access to this directories (pathnames _with_ trailing slashes) 41 | // 42 | // $ALLOWED_DIRS = array('/var/lib/firebird/2.5/data/', 43 | // '/tmp/'); 44 | $ALLOWED_DIRS = array(); 45 | 46 | // if $ALLOWED_FILES is not empty, only the listed databases are allowed to open; 47 | // if this is set the $ALLOWED_DIRS are ignored 48 | // 49 | // $ALLOWED_FILES=array('/var/lib/firebird/2.5/data/employee.fdb', 50 | // '/var/lib/firebird/2.5/data/test.gdb', 51 | // 'employee.fdb' 52 | // ); 53 | $ALLOWED_FILES = array(); 54 | 55 | define('BACKUP_DIR', '/var/lib/firebird/2.5'); // define this to restrict the location for backup files 56 | 57 | define('LANGUAGE', 'english'); // set the default language to use; 58 | 59 | // uncomment the corresponding line for every panel 60 | // you want to not appear in the application 61 | $HIDE_PANELS = array( 62 | // 'db_create', // Create Database 63 | // 'db_delete', // Delete Database 64 | // 'db_systable', // System Tables 65 | // 'db_meta', // Metadata 66 | // 'tb_show', // View Tables 67 | // 'tb_create', // Create New Table 68 | // 'tb_modify', // Modify Table 69 | // 'tb_delete', // Delete Table 70 | // 'acc_index', // Indexes 71 | // 'acc_gen', // Generators 72 | // 'acc_trigger', // Triggers 73 | // 'acc_proc', // Stored Procedures 74 | // 'acc_domain', // Domains 75 | // 'acc_views', // Views 76 | // 'acc_exc', // Exceptions 77 | // 'acc_udf', // User Defined Functions 78 | // 'sql_enter', // Enter Command or Script 79 | // 'sql_output', // Show Output 80 | // 'dt_enter', // Enter Data 81 | // 'dt_export', // Export Data 82 | // 'dt_import', // Import Data 83 | // 'tb_watch', // Watch Table 84 | // 'usr_user', // Users 85 | // 'usr_role', // Roles 86 | // 'usr_cust', // Customizing 87 | // 'adm_server', // Server Statistics 88 | // 'adm_dbstat', // Database Statistics 89 | // 'adm_gfix', // Database Maintenance 90 | // 'adm_backup', // Backup 91 | // 'adm_restore' // Restore 92 | ); 93 | 94 | // use this array to disable the execution of commands or command groups 95 | // from the sql-enter panel 96 | $SQL_DISABLE = array('CREATE DATABASE', // disables creation of databases/schemas; there is no need to 97 | 'CREATE SCHEMA'// add entries for [ALTER|DROP] DATABASE because they did not work anyhow. 98 | // 'DROP' // uncommenting this disables all DROP statements 99 | // 'DROP TABLE' // uncommenting this disables the DROP TABLE statement 100 | ); 101 | 102 | define('SYSDBA_GET_ALL', true); // if TRUE the $HIDE_PANELS and the $SQL_DISABLE settings have 103 | // no effect for the SYSDBA user 104 | 105 | 106 | define('CONFIRM_DELETE', true); // ask for confirmation when deleting data rows or any database objects 107 | 108 | define('SQL_AREA_COLS', 80); // use this for the textarea on the SQL page (also used on the triggers, 109 | define('SQL_AREA_ROWS', 6); // the stored procedures and the views panels) 110 | 111 | define('IFRAME_HEIGHT', 350); // height in pixels for iframes 112 | 113 | define('SQL_MAXSAVE', 100); // defines the maximal line count to save in the session; 114 | // if '0' the whole content will be saved; if the content of the 115 | // textarea is bigger, nothing will be saved 116 | 117 | define('SQL_HISTORY_SIZE', 25); // number of entries in the the sql history buffer 118 | 119 | define('SHOW_OUTPUT_ROWS', 100); // number of rows to display on the sql_output-panel, 120 | // unless the 'Display All' button was hit 121 | 122 | define('DATA_MAXWIDTH', 50); // maximal width for the input fields on the dt_enter-panel 123 | 124 | define('FKLOOKUP_ENTRIES', 1000); 125 | 126 | define('MAX_CSV_LINE', 50000); // maximal length for a line read from the csv import file 127 | 128 | 129 | define('DEFAULT_ROWS', 25); // number of rows to dispay in the watch-panel by default 130 | 131 | define('BLOB_WINDOW_WIDTH', 600); // default dimensions for the blob displaying windows 132 | define('BLOB_WINDOW_HEIGHT', 800); 133 | 134 | define('SESSION_NAME', 'firebirdwebadmin'); // session name to use 135 | 136 | # transaction parameters used for the calls of fbird_trans() 137 | define('TRANS_READ', IBASE_COMMITTED | IBASE_NOWAIT | IBASE_READ); 138 | define('TRANS_WRITE', IBASE_COMMITTED | IBASE_NOWAIT | IBASE_WRITE); 139 | 140 | define('META_REDIRECT', false); // use server (FALSE) or client (TRUE) side redirection 141 | 142 | 143 | define('DEBUG', false); // if TRUE print the $debug[] to the info-panel 144 | define('DEBUG_HTML', false); // if TRUE write the output_buffer to TMPPATH/{scriptname}.html before 145 | // sending it to the client 146 | define('DEBUG_COMMANDS', false); // if TRUE all calls of external commands are diplayed on the info-panel 147 | define('DEBUG_FILES', true); // if TRUE the temporary files created in TMPATH for processing by isql 148 | // are not deleted when isql is finished 149 | 150 | 151 | if ('' != SESSION_NAME) { 152 | session_name(SESSION_NAME); 153 | } 154 | 155 | if (DEBUG === true) { 156 | error_reporting(E_ALL | E_NOTICE | E_STRICT); 157 | } 158 | -------------------------------------------------------------------------------- /inc/debug_funcs.inc.php: -------------------------------------------------------------------------------- 1 | 5 | // Copyright (c) 2000, 2001, 2002, 2003, 2004 by Lutz Brueckner, 6 | // published under the terms of the GNU General Public Licence v.2, 7 | // see file LICENCE for details 8 | 9 | // 10 | // write the content of php's output_buffer to $fname 11 | // 12 | function write_output_buffer($fname) 13 | { 14 | $fp = fopen($fname, 'w') 15 | or die('Error opening file '.$fname); 16 | fwrite($fp, ob_get_contents()) 17 | or die('Error writing to file '.$fname); 18 | ob_end_flush(); 19 | } 20 | 21 | // 22 | // output the distance between $start and $end, 23 | // which are resultstrings from microtime() 24 | // 25 | function show_time_consumption($start, $end) 26 | { 27 | list($sm, $ss) = explode(' ', $start); 28 | list($em, $es) = explode(' ', $end); 29 | $elapsed = $es - $ss + $em - $sm; 30 | echo 'time consumption: '.$elapsed."
\n"; 31 | } 32 | 33 | // add a string to array $debug[], $debug[] is printed on the info-panel if DEBUG == TRUE 34 | // call this function with one or three parameters: 35 | // 36 | // $str : if $$str is a variable print its name and value, else just print $str 37 | // $file, $line : are thought to be __FILE__ and __LINE__ at the place the function is called 38 | // 39 | function add_debug($str, $file = null, $line = null) 40 | { 41 | if ($file == null || $line == null) { 42 | $dstr = "\n"; 43 | if (isset($GLOBALS[$str])) { 44 | $dstr .= add_var_debug($str, "
\n"); 45 | } else { 46 | $dstr .= "$str
\n"; 47 | } 48 | } else { 49 | $dstr = "\n$file, $line:\n"; 50 | if (isset($GLOBALS[$str])) { 51 | $dstr .= ''.add_var_debug($str, "
\n"); 52 | } else { 53 | $dstr .= "$str
\n"; 54 | } 55 | } 56 | $dstr .= "\n\n"; 57 | $GLOBALS['debug'][] = $dstr; 58 | } 59 | 60 | function add_var_debug($var, $separator) 61 | { 62 | if (!is_array($GLOBALS[$var])) { 63 | return($var.' = '.$GLOBALS[$var]); 64 | } else { 65 | $str = $var.' = array('.$separator; 66 | $arr = $GLOBALS[$var]; 67 | foreach ($arr as $key => $val) { 68 | $str .= $key.' => '.$val.$separator; 69 | } 70 | $str .= ')'.$separator; 71 | 72 | return $str; 73 | } 74 | } 75 | 76 | // 77 | // append debugging output $str to the file debug.txt in the temporay directory 78 | // 79 | function file_debug($str) 80 | { 81 | include_once 'inc/configuration.inc.php'; 82 | 83 | $fp = fopen(TMPPATH.'debug.txt', 'a') or die('Error: cannot open file for debug output'); 84 | fwrite($fp, $str); 85 | fclose($fp); 86 | } 87 | 88 | // 89 | // pop up a javascript window displaying $string 90 | // 91 | function js_alert($string) 92 | { 93 | ?> 94 | 100 | 'HTML4_Text'), 125 | array('mode' => 'normal', 126 | 'offset' => 3, 127 | 'before_type' => '', 128 | 'after_type' => '', 129 | 'before_value' => '', 130 | 'after_value' => '', 131 | ) 132 | ); 133 | Var_Dump::display($var); 134 | } else { 135 | echo "
\n";
136 |         print_r($var);
137 |         echo "
\n"; 138 | } 139 | } 140 | 141 | ?> 142 | -------------------------------------------------------------------------------- /inc/display_variable.php: -------------------------------------------------------------------------------- 1 | 5 | // Copyright (c) 2000, 2001, 2002, 2003, 2004 by Lutz Brueckner, 6 | // published under the terms of the GNU General Public Licence v.2, 7 | // see file LICENCE for details 8 | 9 | require './configuration.inc.php'; 10 | require './debug_funcs.inc.php'; 11 | 12 | session_start(); 13 | 14 | switch ($_GET['var']) { 15 | case 'SESSION': 16 | $display = $_SESSION; 17 | break; 18 | case 'POST': 19 | case 'GET': 20 | $display = $_SESSION['s_'.$_GET['var']]; 21 | break; 22 | default: 23 | $display = null; 24 | } 25 | 26 | debug_var($display); 27 | -------------------------------------------------------------------------------- /inc/exceptions.inc.php: -------------------------------------------------------------------------------- 1 | 5 | // Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005 by Lutz Brueckner, 6 | // published under the terms of the GNU General Public Licence v.2, 7 | // see file LICENCE for details 8 | 9 | 10 | // 11 | // return an array with the properties of the exceptions defined in the database 12 | // 13 | function get_exceptions($order = 1, $dir = 'ASC') 14 | { 15 | global $dbhandle; 16 | 17 | $sql = 'SELECT E.RDB$EXCEPTION_NAME AS ENAME,' 18 | . ' E.RDB$MESSAGE AS MSG' 19 | . ' FROM RDB$EXCEPTIONS E' 20 | . ' ORDER BY ' . $order . ' ' . $dir; 21 | $res = fbird_query($dbhandle, $sql) or fb_error(__FILE__, __LINE__, $sql); 22 | 23 | $exceptions = array(); 24 | while ($obj = fbird_fetch_object($res)) { 25 | $exceptions[trim($obj->ENAME)] = trim($obj->MSG); 26 | } 27 | 28 | return $exceptions; 29 | } 30 | 31 | // 32 | // return the html displaying the user defined functions in a table 33 | // 34 | function get_exceptions_table($exceptions, $order, $dir) 35 | { 36 | global $acc_strings; 37 | 38 | $heads = array('Name', 'Message'); 39 | 40 | $html = "\n" 41 | . " \n"; 42 | 43 | foreach ($heads as $idx => $head) { 44 | $url = url_session($_SERVER['PHP_SELF'] . '?excorder=1&order=' . ($idx + 1)); 45 | $title = $acc_strings[$head]; 46 | if ($order == $idx + 1) { 47 | $title = $dir == 'ASC' ? '* ' . $title : $title . ' *'; 48 | } 49 | 50 | $html .= ' \n"; 51 | } 52 | 53 | $html .= " \n"; 54 | 55 | foreach ($exceptions as $ename => $msg) { 56 | $html .= " \n" 57 | . ' \n" 58 | . ' \n" 59 | . " \n"; 60 | } 61 | 62 | $html .= "
' . $title . "
' . $ename . "' . $msg . "
\n"; 63 | 64 | return $html; 65 | } 66 | 67 | // 68 | // return the html for a exception selectlist 69 | // 70 | function get_exception_select($name, $sel = null, $empty = true, $tags = array()) 71 | { 72 | global $s_exceptions; 73 | 74 | $enames = array_keys($s_exceptions); 75 | sort($enames); 76 | 77 | return get_selectlist($name, $enames, $sel, $empty, $tags); 78 | } 79 | 80 | // 81 | // create an exception from the definitions in $exception_defs 82 | // 83 | function create_exception($exception_defs) 84 | { 85 | global $dbhandle, $fb_error, $lsql; 86 | 87 | $lsql = 'CREATE EXCEPTION ' . $exception_defs['name'] . " '" . str_replace("'", "''", $exception_defs['msg']) . "'"; 88 | if (DEBUG) { 89 | add_debug('lsql', __FILE__, __LINE__); 90 | } 91 | 92 | if (!@fbird_query($dbhandle, $lsql)) { 93 | $fb_error = fbird_errmsg(); 94 | } 95 | 96 | return empty($fb_error); 97 | } 98 | 99 | // 100 | // create an exception from the definitions in $exception_defs 101 | // 102 | function modify_exception($exception_defs) 103 | { 104 | global $dbhandle, $fb_error, $lsql; 105 | 106 | $lsql = 'ALTER EXCEPTION ' . $exception_defs['name'] . " '" . str_replace("'", "''", $exception_defs['msg']) . "'"; 107 | if (DEBUG) { 108 | add_debug('lsql', __FILE__, __LINE__); 109 | } 110 | 111 | if (!@fbird_query($dbhandle, $lsql)) { 112 | $fb_error = fbird_errmsg(); 113 | } 114 | 115 | return empty($fb_error); 116 | } 117 | 118 | // 119 | // drop the user defined function $name off the database 120 | // 121 | function drop_exception($name) 122 | { 123 | global $s_exceptions, $dbhandle; 124 | global $fb_error, $lsql; 125 | 126 | $lsql = 'DROP EXCEPTION ' . $name; 127 | if (DEBUG) { 128 | add_debug('lsql', __FILE__, __LINE__); 129 | } 130 | if (!@fbird_query($dbhandle, $lsql)) { 131 | $fb_error = fbird_errmsg(); 132 | 133 | return false; 134 | } else { 135 | unset($s_exceptions[$name]); 136 | 137 | return true; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /inc/foreign_keys.inc.php: -------------------------------------------------------------------------------- 1 | 5 | // Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005 by Lutz Brueckner, 6 | // published under the terms of the GNU General Public Licence v.2, 7 | // see file LICENCE for details 8 | 9 | // 10 | // find the foreign keys defined for $table, 11 | // only foreign keys over single columns are taken into consideration 12 | // 13 | function get_foreignkeys($tablename, $privilege = null) 14 | { 15 | $sql = 'SELECT I2.RDB$RELATION_NAME FKTABLE,' 16 | .' IS1.RDB$FIELD_NAME FKFIELD,' 17 | .' IS2.RDB$FIELD_NAME TFIELD' 18 | .' FROM RDB$RELATION_CONSTRAINTS RC' 19 | .' INNER JOIN RDB$INDICES I1 ON RC.RDB$INDEX_NAME=I1.RDB$INDEX_NAME' 20 | .' INNER JOIN RDB$INDICES I2 ON I1.RDB$FOREIGN_KEY=I2.RDB$INDEX_NAME' 21 | .' INNER JOIN RDB$INDEX_SEGMENTS IS1 ON I2.RDB$INDEX_NAME=IS1.RDB$INDEX_NAME' 22 | .' INNER JOIN RDB$INDEX_SEGMENTS IS2 ON I1.RDB$INDEX_NAME=IS2.RDB$INDEX_NAME' 23 | ." WHERE RC.RDB\$RELATION_NAME='".$tablename."'" 24 | ." AND RC.RDB\$CONSTRAINT_TYPE='FOREIGN KEY'" 25 | .' AND I1.RDB$SEGMENT_COUNT=1'; 26 | 27 | $res = @fbird_query($GLOBALS['dbhandle'], $sql) or fb_error(__FILE__, __LINE__, $sql); 28 | 29 | $fk = array(); 30 | while ($row = fbird_fetch_object($res)) { 31 | $fktable = trim($row->FKTABLE); 32 | if (empty($privilege) || in_array($privilege, $GLOBALS['s_tables'][$fktable]['privileges'])) { 33 | $fk[trim($row->TFIELD)] = array('table' => $fktable, 34 | 'column' => trim($row->FKFIELD), 35 | ); 36 | } 37 | } 38 | fbird_free_result($res); 39 | 40 | return $fk; 41 | } 42 | 43 | // 44 | // return TRUE if the table $tablename contains a column with a foreign key definition 45 | // 46 | function have_fk($tablename) 47 | { 48 | return count(array_filter($GLOBALS['s_fields'][$tablename], function($a) {return isset($a["foreign"]);} )) > 0; 49 | } 50 | 51 | // 52 | // return infos about a tables foreign keys in an array 53 | // 54 | function get_fk_lookups_data($tablename, $fk_lookups) 55 | { 56 | $lookups_data = array(); 57 | $fk_defs = get_foreignkeys($tablename, 'S'); 58 | foreach ($fk_defs as $colname => $defs) { 59 | 60 | // skip foreign keys with more than FKLOOKUP_ENTRIES values 61 | if (!isset($GLOBALS['s_tables'][$defs['table']]['count'])) { 62 | $GLOBALS['s_tables'][$defs['table']]['count'] = get_table_count($defs['table']); 63 | } 64 | if ($GLOBALS['s_tables'][$defs['table']]['count'] > FKLOOKUP_ENTRIES) { 65 | continue; 66 | } 67 | 68 | $value_field = ifsetor($fk_lookups[$colname], $defs['column']); 69 | if ($value_field != $defs['column']) { 70 | $value_field = 'COALESCE('.$value_field.", '')"." || ' - '".' || '.$defs['column']; 71 | } 72 | 73 | $sql = 'SELECT '.$defs['column'].', '.$value_field.' FROM '.$defs['table'].' ORDER BY '.$value_field.' ASC'; 74 | $res = fbird_query($GLOBALS['dbhandle'], $sql) or fb_error(__FILE__, __LINE__, $sql); 75 | 76 | $data = array(); 77 | while ($row = fbird_fetch_row($res)) { 78 | $data[trim($row[0])] = trim($row[1]); 79 | } 80 | fbird_free_result($res); 81 | 82 | $lookups_data[$colname] = array('table' => $defs['table'], 83 | 'column' => $defs['column'], 84 | 'data' => $data, ); 85 | } 86 | 87 | return $lookups_data; 88 | } 89 | -------------------------------------------------------------------------------- /inc/handle_editdata.inc.php: -------------------------------------------------------------------------------- 1 | 5 | // Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005 by Lutz Brueckner, 6 | // published under the terms of the GNU General Public Licence v.2, 7 | // see file LICENCE for details 8 | 9 | // 10 | // check if and which 'done' or 'cancel' button on which dt_edit panel was clicked 11 | // 12 | 13 | foreach ($_POST as $name => $value) { 14 | if (preg_match('/dt_edit_(cancel|save)_([0-9]+)/', $name, $matches)) { 15 | 16 | // index for array $s_edit_where[] 17 | $instance = $matches[2]; 18 | $table = $s_edit_where[$instance]['table']; 19 | $job = $matches[1]; 20 | $success = false; 21 | if ($job == 'save') { 22 | 23 | // the origin types of domain-based columns are needed 24 | if (!$s_domains_valid) { 25 | include_once './inc/domains.inc.php'; 26 | 27 | $s_domains = get_domain_definitions($s_domains); 28 | $s_domains_valid = true; 29 | } 30 | 31 | $bindargs = $cols = $s_edit_values[$instance] = array(); 32 | $k = 0; 33 | foreach ($s_fields[$table] as $field) { 34 | if (isset($field['comp'])) { 35 | $s_edit_values[$instance][] = $field['csource']; 36 | ++$k; 37 | continue; 38 | } 39 | 40 | if (isset($_FILES['dt_edit_file_'.$instance.'_'.$k]) && 41 | !empty($_FILES['dt_edit_file_'.$instance.'_'.$k]['name'])) { 42 | $value = $_FILES['dt_edit_file_'.$instance.'_'.$k]; 43 | $s_edit_values[$instance][] = $value; 44 | } else { 45 | $value = get_request_data('dt_edit_field_'.$instance.'_'.$k); 46 | $s_edit_values[$instance][] = $value; 47 | } 48 | 49 | // type of the field or the origin type of a domain-based field 50 | $type = !isset($field['domain']) ? $field['type'] : $s_domains[$field['type']]['type']; 51 | 52 | switch ($type) { 53 | case 'CHARACTER' : 54 | case 'VARCHAR' : 55 | case 'DATE' : 56 | case 'TIME' : 57 | case 'TIMESTAMP' : 58 | $bindargs[] = empty($field['notnull']) && empty($value) ? null : $value; 59 | break; 60 | case 'BLOB' : 61 | // blob from file-upload 62 | if (is_array($value) && strlen(trim($value['name'])) > 0) { 63 | $bfname = $value['tmp_name']; 64 | $bfhandle = fopen($bfname, 'r') or die('cannot open file '.$bfname); 65 | $bstr = fbird_blob_import($dbhandle, $bfhandle); 66 | fclose($bfhandle); 67 | $bindargs[] = $bstr; 68 | } 69 | // drop blob checkbox 70 | elseif (isset($_POST['dt_edit_drop_blob_'.$instance.'_'.$k]) 71 | && empty($field['notnull'])) { 72 | $bindargs[] = null; 73 | } 74 | // blob from textarea 75 | elseif (!empty($value)) { 76 | $bhandle = fbird_blob_create($dbhandle) or die('cannot create blob: '.__FILE__.', '.__LINE__); 77 | fbird_blob_add($bhandle, $value); 78 | $bstr = fbird_blob_close($bhandle); 79 | $bindargs[] = $bstr; 80 | } else { 81 | $bindargs[] = null; 82 | } 83 | break; 84 | default: 85 | if ($value == '') { 86 | $value = null; 87 | } 88 | $bindargs[] = empty($field['notnull']) && strlen($value) == 0 ? null : $value; 89 | } 90 | $cols[] = $field['name']; 91 | ++$k; 92 | } 93 | 94 | if (count($bindargs) > 0) { 95 | $fb_error = $s_cust['enter']['as_new'] == true 96 | ? insert_row($table, $cols, $bindargs) 97 | : update_row($table, $cols, $bindargs, substr($s_edit_where[$instance]['where'], 6)); 98 | 99 | if (empty($fb_error)) { 100 | $success = true; 101 | $s_enter_values = array(); 102 | $s_watch_buffer = ''; 103 | 104 | // cleanup the watchtable output buffer 105 | $s_watch_buffer = ''; 106 | } 107 | } 108 | } 109 | 110 | $panels_arrayname = get_panel_array($_SERVER['SCRIPT_NAME']); 111 | 112 | if ($success || $job == 'cancel') { 113 | // remove the dt_edit panel 114 | $name = 'dt_edit'.$instance; 115 | $idx = get_panel_index($$panels_arrayname, $name); 116 | array_splice($$panels_arrayname, $idx, 1); 117 | unset($s_edit_where[$instance]); 118 | unset($s_edit_values[$instance]); 119 | if (count($s_edit_where) == 0) { 120 | $s_edit_idx = 0; 121 | } 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /inc/kill_session.php: -------------------------------------------------------------------------------- 1 | 5 | // Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005 by Lutz Brueckner, 6 | // published under the terms of the GNU General Public Licence v.2, 7 | // see file LICENCE for details 8 | 9 | // 10 | // create a role called $name 11 | // 12 | function create_role($name) 13 | { 14 | global $dbhandle, $roles, $s_login; 15 | global $fb_error, $lsql; 16 | 17 | $name = strtoupper($name); 18 | 19 | $lsql = 'CREATE ROLE '.$name; 20 | 21 | if (DEBUG) { 22 | add_debug('lsql', __FILE__, __LINE__); 23 | } 24 | 25 | if (!@fbird_query($dbhandle, $lsql)) { 26 | $fb_error = fbird_errmsg(); 27 | } 28 | 29 | if (empty($fb_error)) { 30 | $roles[$name]['owner'] = $s_login['user']; 31 | $roles[$name]['members'] = array(); 32 | 33 | return true; 34 | } else { 35 | return false; 36 | } 37 | } 38 | 39 | // 40 | // drop the role $name off the database 41 | // 42 | function drop_role($name) 43 | { 44 | global $roles, $dbhandle; 45 | global $fb_error, $lsql; 46 | 47 | $lsql = 'DROP ROLE '.$name; 48 | if (DEBUG) { 49 | add_debug('lsql', __FILE__, __LINE__); 50 | } 51 | if (!@fbird_query($dbhandle, $lsql)) { 52 | $fb_error = fbird_errmsg(); 53 | 54 | return false; 55 | } else { 56 | unset($roles[$name]); 57 | 58 | return true; 59 | } 60 | } 61 | 62 | // 63 | // grant a role to an user 64 | // 65 | function grant_role_to_user($role, $user) 66 | { 67 | global $dbhandle, $roles; 68 | global $fb_error, $lsql; 69 | 70 | $user = strtoupper($user); 71 | 72 | $lsql = 'GRANT '.$role.' TO '.$user; 73 | 74 | if (DEBUG) { 75 | add_debug('lsql', __FILE__, __LINE__); 76 | } 77 | 78 | if (!@fbird_query($dbhandle, $lsql)) { 79 | $fb_error = fbird_errmsg(); 80 | } 81 | 82 | if (empty($fb_error)) { 83 | $roles[$role]['members'][] = $user; 84 | 85 | return true; 86 | } else { 87 | return false; 88 | } 89 | } 90 | 91 | // 92 | // revoke a role from an user 93 | // 94 | function revoke_role_from_user($role, $user) 95 | { 96 | global $dbhandle, $roles; 97 | global $fb_error, $lsql; 98 | 99 | $user = strtoupper($user); 100 | 101 | $lsql = 'REVOKE '.$role.' FROM '.$user; 102 | 103 | if (DEBUG) { 104 | add_debug('lsql', __FILE__, __LINE__); 105 | } 106 | 107 | if (!@fbird_query($dbhandle, $lsql)) { 108 | $fb_error = fbird_errmsg(); 109 | } 110 | 111 | if (empty($fb_error) && 112 | ($idx = array_search($user, $roles[$role]['members'])) !== false) { 113 | unset($roles[$role]['members'][$idx]); 114 | 115 | return true; 116 | } else { 117 | return false; 118 | } 119 | } 120 | 121 | // 122 | // return an array with the properties of the defined indeces 123 | // 124 | function get_roles() 125 | { 126 | global $dbhandle; 127 | 128 | $sql = 'SELECT R.RDB$ROLE_NAME AS NAME,' 129 | .' R.RDB$OWNER_NAME AS OWNER,' 130 | .' P.RDB$USER AS MEMBER' 131 | .' FROM RDB$ROLES R' 132 | .' LEFT JOIN RDB$USER_PRIVILEGES P' 133 | .' ON R.RDB$ROLE_NAME=P.RDB$RELATION_NAME' 134 | ." AND P.RDB\$PRIVILEGE='M'" 135 | .'ORDER BY R.RDB$ROLE_NAME'; 136 | $res = fbird_query($dbhandle, $sql) or fb_error(); 137 | 138 | $roles = array(); 139 | $lastone = ''; 140 | while ($obj = fbird_fetch_object($res)) { 141 | $rname = trim($obj->NAME); 142 | $member = (isset($obj->MEMBER)) ? trim($obj->MEMBER) : ''; 143 | 144 | if ($rname == $lastone) { 145 | $roles[$rname]['members'][] = $member; 146 | continue; 147 | } 148 | 149 | $roles[$rname]['owner'] = trim($obj->OWNER); 150 | $roles[$rname]['members'] = (!empty($member)) ? array($member) : array(); 151 | $lastone = $rname; 152 | } 153 | 154 | return $roles; 155 | } 156 | 157 | // 158 | // output the options for the role selectlist 159 | // 160 | function build_roles_options($roles, $selected) 161 | { 162 | global $s_login; 163 | 164 | echo "