* Copyright (c) 2001-2002 Jim Kraai * Versions 5.0 and higher developed by Ondrej Jombik * Copyright (c) 2002-2006 Platon Group, http://platon.sk/ * All rights reserved. * * See README file for more information about this software. * See COPYING file for license information. * * Download the latest version from * http://platon.sk/projects/phpMyEdit/ */ /* $Platon: phpMyEdit/phpMyEdit.class.php,v 1.208 2007-09-22 14:45:50 michal Exp $ */ /* This is a generic table editing program. The table and fields to be edited are defined in the calling program. This program works in three passes. * Pass 1 (the last part of the program) displays the selected SQL table in a scrolling table on the screen. Radio buttons are used to select a record for editing or deletion. If the user chooses Add, Change, Copy, View or Delete buttons. * Pass 2 starts, displaying the selected record. If the user chooses the Save button from this screen. * Pass 3 processes the update and the display returns to the original table view (Pass 1). */ class phpMyEdit_timer /* {{{ */ { var $startTime; var $started; function phpMyEdit_timer($start = true) { $this->started = false; if ($start) { $this->start(); } } function start() { $startMtime = explode(' ', microtime()); $this->startTime = (double) $startMtime[0] + (double) $startMtime[1]; $this->started = true; } function end($iterations = 1) { // get the time, check whether the timer was started later $endMtime = explode(' ', microtime()); if ($this->started) { $endTime = (double)($endMtime[0])+(double)($endMtime[1]); $dur = $endTime - $this->startTime; $avg = 1000 * $dur / $iterations; $avg = round(1000 * $avg) / 1000; return $avg; } else { return 'phpMyEdit_timer ERROR: timer not started'; } } } /* }}} */ if (! function_exists('array_search')) { /* {{{ */ function array_search($needle, $haystack) { foreach ($haystack as $key => $value) { if ($needle == $value) return $key; } return false; } } /* }}} */ if (! function_exists('realpath')) { /* {{{ */ function realpath($path) { return $path; } } /* }}} */ class phpMyEdit { // Class variables {{{ // Database handling var $hn; // hostname var $un; // user name var $pw; // password var $tb; // table var $db; // database var $dbp; // database with point and delimiters var $dbh; // database handle var $close_dbh; // if database handle should be closed // Record manipulation var $key; // name of field which is the unique key var $key_num; // number of field which is the unique key var $key_type; // type of key field (int/real/string/date etc.) var $key_delim; // character used for key value quoting var $rec; // number of record selected for editing var $inc; // number of records to display var $fm; // first record to display var $fl; // is the filter row displayed (boolean) var $fds; // sql field names var $fdn; // sql field names => $k var $num_fds; // number of fields var $options; // options for users: ACDFVPI var $fdd; // field definitions var $qfn; // value of all filters used during the last pass var $sfn; // sort field number (- = descending sort order) var $cur_tab; // current selected tab // Operation var $navop; // navigation buttons/operations var $sw; // filter display/hide/clear button var $operation; // operation to do: Add, Change, Delete var $saveadd; var $moreadd; var $canceladd; var $savechange; var $morechange; var $cancelchange; var $savecopy; var $cancelcopy; var $savedelete; var $canceldelete; var $cancelview; // Additional features var $labels; // multilingual labels var $cgi; // CGI variable features array var $js; // JS configuration array var $dhtml; // DHTML configuration array var $url; // URL array var $message; // informational message to print var $notify; // change notification e-mail adresses var $logtable; // name of optional logtable var $navigation; // navigation style var $tabs; // TAB names var $timer = null; // phpMyEdit_timer object var $sd; var $ed; // sql start and end delimiters '`' in case of MySQL // Predefined variables var $comp_ops = array('<'=>'<','<='=>'<=','='=>'=','>='=>'>=','>'=>'>'); var $sql_aggrs = array( 'sum' => 'Total', 'avg' => 'Average', 'min' => 'Minimum', 'max' => 'Maximum', 'count' => 'Count'); var $page_types = array( 'L' => 'list', 'F' => 'filter', 'A' => 'add', 'V' => 'view', 'C' => 'change', 'P' => 'copy', 'D' => 'delete' ); var $default_buttons = array( 'L' => array('<<','<','add','view','change','copy','delete','>','>>','goto','goto_combo'), 'F' => array('<<','<','add','view','change','copy','delete','>','>>','goto','goto_combo'), 'A' => array('save','more','cancel'), 'C' => array('save','more','cancel'), 'P' => array('save', 'cancel'), 'D' => array('save','cancel'), 'V' => array('change','cancel') ); // }}} /* * column specific functions */ function col_has_sql($k) { return isset($this->fdd[$k]['sql']); } function col_has_sqlw($k) { return isset($this->fdd[$k]['sqlw']) && !$this->virtual($k); } function col_has_values($k) { return isset($this->fdd[$k]['values']) || isset($this->fdd[$k]['values2']); } function col_has_php($k) { return isset($this->fdd[$k]['php']); } function col_has_URL($k) { return isset($this->fdd[$k]['URL']) || isset($this->fdd[$k]['URLprefix']) || isset($this->fdd[$k]['URLpostfix']); } function col_has_multiple($k) { return $this->col_has_multiple_select($k) || $this->col_has_checkboxes($k); } function col_has_multiple_select($k) { return $this->fdd[$k]['select'] == 'M' && ! $this->fdd[$k]['values']['table']; } function col_has_checkboxes($k) { return $this->fdd[$k]['select'] == 'C' && ! $this->fdd[$k]['values']['table']; } function col_has_radio_buttons($k) { return $this->fdd[$k]['select'] == 'O' && ! $this->fdd[$k]['values']['table']; } function col_has_datemask($k) { return isset($this->fdd[$k]['datemask']) || isset($this->fdd[$k]['strftimemask']); } /* * functions for indicating whether navigation style is enabled */ function nav_buttons() { return stristr($this->navigation, 'B'); } function nav_text_links() { return stristr($this->navigation, 'T'); } function nav_graphic_links() { return stristr($this->navigation, 'G'); } function nav_up() { return (stristr($this->navigation, 'U') && !($this->buttons[$this->page_type]['up'] === false)); } function nav_down() { return (stristr($this->navigation, 'D') && !($this->buttons[$this->page_type]['down'] === false)); } /* * functions for indicating whether operations are enabled */ function add_enabled() { return stristr($this->options, 'A'); } function change_enabled() { return stristr($this->options, 'C'); } function delete_enabled() { return stristr($this->options, 'D'); } function filter_enabled() { return stristr($this->options, 'F'); } function view_enabled() { return stristr($this->options, 'V'); } function copy_enabled() { return stristr($this->options, 'P') && $this->add_enabled(); } function tabs_enabled() { return $this->display['tabs'] && count($this->tabs) > 0; } function hidden($k) { return stristr($this->fdd[$k]['input'],'H'); } function password($k) { return stristr($this->fdd[$k]['input'],'W'); } function readonly($k) { return stristr($this->fdd[$k]['input'],'R') || $this->virtual($k); } function virtual($k) { return stristr($this->fdd[$k]['input'],'V') && $this->col_has_sql($k); } function add_operation() { return $this->operation == $this->labels['Add'] && $this->add_enabled(); } function change_operation() { return $this->operation == $this->labels['Change'] && $this->change_enabled(); } function copy_operation() { return $this->operation == $this->labels['Copy'] && $this->copy_enabled(); } function delete_operation() { return $this->operation == $this->labels['Delete'] && $this->delete_enabled(); } function view_operation() { return $this->operation == $this->labels['View'] && $this->view_enabled(); } function filter_operation() { return $this->fl && $this->filter_enabled() && $this->list_operation(); } function list_operation() { /* covers also filtering page */ return ! $this->change_operation() && ! $this->add_operation() && ! $this->copy_operation() && ! $this->delete_operation() && ! $this->view_operation(); } function next_operation() { return ($this->navop == $this->labels['Next']) || ($this->navop == '>'); } function prev_operation() { return ($this->navop == $this->labels['Prev']) || ($this->navop == '<'); } function first_operation() { return ($this->navop == $this->labels['First']) || ($this->navop == '<<'); } function last_operation() { return ($this->navop == $this->labels['Last']) || ($this->navop == '>>'); } function clear_operation() { return $this->sw == $this->labels['Clear']; } function add_canceled() { return $this->canceladd == $this->labels['Cancel']; } function view_canceled() { return $this->cancelview == $this->labels['Cancel']; } function change_canceled() { return $this->cancelchange == $this->labels['Cancel']; } function copy_canceled() { return $this->cancelcopy == $this->labels['Cancel']; } function delete_canceled() { return $this->canceldelete == $this->labels['Cancel']; } function is_values2($k, $val = 'X') /* {{{ */ { return $val === null || (isset($this->fdd[$k]['values2']) && !isset($this->fdd[$k]['values']['table'])); } /* }}} */ function processed($k) /* {{{ */ { if ($this->virtual($k)) { return false; } $options = @$this->fdd[$k]['options']; if (! isset($options)) { return true; } return ($this->saveadd == $this->labels['Save'] && stristr($options, 'A')) || ($this->moreadd == $this->labels['More'] && stristr($options, 'A')) || ($this->savechange == $this->labels['Save'] && stristr($options, 'C')) || ($this->morechange == $this->labels['Apply'] && stristr($options, 'C')) || ($this->savecopy == $this->labels['Save'] && stristr($options, 'P')) || ($this->savedelete == $this->labels['Save'] && stristr($options, 'D')); } /* }}} */ function displayed($k) /* {{{ */ { if (is_numeric($k)) { $k = $this->fds[$k]; } $options = @$this->fdd[$k]['options']; if (! isset($options)) { return true; } return ($this->add_operation() && stristr($options, 'A')) || ($this->view_operation() && stristr($options, 'V')) || ($this->change_operation() && stristr($options, 'C')) || ($this->copy_operation() && stristr($options, 'P')) || ($this->delete_operation() && stristr($options, 'D')) || ($this->filter_operation() && stristr($options, 'F')) || ($this->list_operation() && stristr($options, 'L')); } /* }}} */ function debug_var($name, $val) /* {{{ */ { if (is_array($val) || is_object($val)) { echo "
$name\n";
			ob_start();
			//print_r($val);
			var_dump($val);
			$content = ob_get_contents();
			ob_end_clean();
			echo htmlspecialchars($content);
			echo "
\n"; } else { echo 'debug_var()::',htmlspecialchars($name),''; echo '::',htmlspecialchars($val),'::',"
\n"; } } /* }}} */ /* * sql functions */ function sql_connect() /* {{{ */ { $this->dbh = @ini_get('allow_persistent') ? @mysql_pconnect($this->hn, $this->un, $this->pw) : @mysql_connect($this->hn, $this->un, $this->pw); } /* }}} */ function sql_disconnect() /* {{{ */ { if ($this->close_dbh) { @mysql_close($this->dbh); $this->dbh = null; } } /* }}} */ function sql_fetch(&$res, $type = 'a') /* {{{ */ { if($type == 'n') $type = MYSQL_NUM; else $type = MYSQL_ASSOC; return @mysql_fetch_array($res, $type); } /* }}} */ function sql_free_result(&$res) /* {{{ */ { return @mysql_free_result($res); } /* }}} */ function sql_affected_rows(&$dbh) /* {{{ */ { return @mysql_affected_rows($dbh); } /* }}} */ function sql_field_len(&$res,$field) /* {{{ */ { return @mysql_field_len($res, $field); } /* }}} */ function sql_insert_id() /* {{{ */ { return mysql_insert_id($this->dbh); } /* }}} */ function sql_limit($start, $more) /* {{{ */ { if($more < 0) return; return ' LIMIT '.$start.', '.$more.' '; } /* }}} */ function sql_delimiter() /* {{{ */ { $this->sd = '`'; $this->ed='`'; return $this->sd; } /* }}} */ function myquery($qry, $line = 0, $debug = 0) /* {{{ */ { global $debug_query; if ($debug_query || $debug) { $line = intval($line); echo '

MySQL query at line ',$line,'

',htmlspecialchars($qry),'
',"\n"; } if (isset($this->db)) { $ret = @mysql_db_query($this->db, $qry, $this->dbh); } else { $ret = @mysql_query($qry, $this->dbh); } if (! $ret) { echo '

MySQL error ',mysql_errno($this->dbh),'

'; echo htmlspecialchars(mysql_error($this->dbh)),'
',"\n"; } return $ret; } /* }}} */ /* end of sql functions */ function make_language_labels($language) /* {{{ */ { // just try the first language and variant // this isn't content-negotiation rfc compliant $language = strtoupper($language); // try the full language w/ variant $file = $this->dir['lang'].'PME.lang.'.$language.'.inc'; while (! file_exists($file)) { $pos = strrpos($language, '-'); if ($pos === false) { $file = $this->dir['lang'].'PME.lang.EN.inc'; break; } $language = substr($language, 0, $pos); $file = $this->dir['lang'].'PME.lang.'.$language.'.inc'; } $ret = @include($file); if (! is_array($ret)) { return $ret; } $small = array( 'Search' => 'v', 'Hide' => '^', 'Clear' => 'X', 'Query' => htmlspecialchars('>')); if ((!$this->nav_text_links() && !$this->nav_graphic_links()) || !isset($ret['Search']) || !isset($ret['Query']) || !isset($ret['Hide']) || !isset($ret['Clear'])) { foreach ($small as $key => $val) { $ret[$key] = $val; } } return $ret; } /* }}} */ function set_values($field_num, $prepend = null, $append = null, $strict = false) /* {{{ */ { return (array) $prepend + (array) $this->fdd[$field_num]['values2'] + (isset($this->fdd[$field_num]['values']['table']) || $strict ? $this->set_values_from_table($field_num, $strict) : array()) + (array) $append; } /* }}} */ function set_values_from_table($field_num, $strict = false) /* {{{ */ { $db = &$this->fdd[$field_num]['values']['db']; $table = $this->sd.$this->fdd[$field_num]['values']['table'].$this->ed; $key = &$this->fdd[$field_num]['values']['column']; $desc = &$this->fdd[$field_num]['values']['description']; $dbp = isset($db) ? $this->sd.$db.$this->ed.'.' : $this->dbp; $qparts['type'] = 'select'; if ($table != $this->sd.$this->ed) { $qparts['select'] = 'DISTINCT '.$table.'.'.$this->sd.$key.$this->ed; if ($desc && is_array($desc) && is_array($desc['columns'])) { $qparts['select'] .= ',CONCAT('; // ) $num_cols = sizeof($desc['columns']); if (isset($desc['divs'][-1])) { $qparts['select'] .= '"'.addslashes($desc['divs'][-1]).'",'; } foreach ($desc['columns'] as $key => $val) { if ($val) { $qparts['select'] .= 'IFNULL(CAST('.$this->sd.$val.$this->ed.' AS CHAR),"")'; if ($desc['divs'][$key]) { $qparts['select'] .= ',"'.addslashes($desc['divs'][$key]).'"'; } $qparts['select'] .= ','; } } $qparts['select']{strlen($qparts['select']) - 1} = ')'; $qparts['select'] .= ' AS '.$this->sd.'PMEalias'.$field_num.$this->ed; $qparts['orderby'] = $this->sd.'PMEalias'.$field_num.$this->ed; } else if ($desc && is_array($desc)) { // TODO } else if ($desc) { $qparts['select'] .= ','.$table.'.'.$this->sd.$desc.$this->ed; $qparts['orderby'] = $this->sd.$desc.$this->ed; } else if ($key) { $qparts['orderby'] = $this->sd.$key.$this->ed; } $qparts['from'] = $dbp.$table; $ar = array( 'table' => $table, 'column' => $column, 'description' => $desc); $qparts['where'] = $this->substituteVars($this->fdd[$field_num]['values']['filters'], $ar); if ($this->fdd[$field_num]['values']['orderby']) { $qparts['orderby'] = $this->substituteVars($this->fdd[$field_num]['values']['orderby'], $ar); } } else { /* simple value extraction */ $key = &$this->fds[$field_num]; $this->virtual($field_num) && $key = $this->fqn($field_num); $qparts['select'] = 'DISTINCT '.$this->sd.$key.$this->ed.' AS PMEkey'; $qparts['orderby'] = 'PMEkey'; $qparts['from'] = $this->dbp.$this->sd.$this->tb.$this->ed; } $values = array(); $res = $this->myquery($this->get_SQL_query($qparts), __LINE__); while ($row = $this->sql_fetch($res, 'n')) { $values[$row[0]] = $desc ? $row[1] : $row[0]; } return $values; } /* }}} */ function fqn($field, $dont_desc = false, $dont_cols = false) /* {{{ */ { is_numeric($field) || $field = array_search($field, $this->fds); // if read SQL expression exists use it if ($this->col_has_sql($field) && !$this->col_has_values($field)) return $this->fdd[$field]['sql']; // on copy/change always use simple key retrieving if ($this->add_operation() || $this->copy_operation() || $this->change_operation()) { $ret = $this->sd.'PMEtable0'.$this->ed.'.'.$this->sd.$this->fds[$field].$this->ed; } else { if ($this->fdd[$this->fds[$field]]['values']['description'] && ! $dont_desc) { $desc = &$this->fdd[$this->fds[$field]]['values']['description']; if (is_array($desc) && is_array($desc['columns'])) { $ret = 'CONCAT('; // ) $num_cols = sizeof($desc['columns']); if (isset($desc['divs'][-1])) { $ret .= '"'.addslashes($desc['divs'][-1]).'",'; } foreach ($desc['columns'] as $key => $val) { if ($val) { $ret .= 'IFNULL(CAST('.$this->sd.'PMEjoin'.$field.$this->ed.'.'.$this->sd.$val.$this->ed.' AS CHAR),"")'; if ($desc['divs'][$key]) { $ret .= ',"'.addslashes($desc['divs'][$key]).'"'; } $ret .= ','; } } $ret{strlen($ret) - 1} = ')'; } else if (is_array($desc)) { // TODO } else { $ret = $this->sd.'PMEjoin'.$field.$this->ed.'.'.$this->sd.$this->fdd[$this->fds[$field]]['values']['description'].$this->ed; } // TODO: remove me } elseif (0 && $this->fdd[$this->fds[$field]]['values']['column'] && ! $dont_cols) { $ret = $this->sd.'PMEjoin'.$field.$this->ed.'.'.$this->fdd[$this->fds[$field]]['values']['column']; } else { $ret = $this->sd.'PMEtable0'.$this->ed.'.'.$this->sd.$this->fds[$field].$this->ed; } // TODO: not neccessary, remove me! if (is_array($this->fdd[$this->fds[$field]]['values2'])) { } } return $ret; } /* }}} */ function get_SQL_main_list_query_parts() /* {{{ */ { /* * Prepare the SQL Query from the data definition file */ $qparts['type'] = 'select'; $qparts['select'] = $this->get_SQL_column_list(); // Even if the key field isn't displayed, we still need its value if ($select_recs) { if (!in_array ($this->key, $this->fds)) { $qparts['select'] .= ','.$this->fqn($this->key); } } $qparts['from'] = $this->get_SQL_join_clause(); $qparts['where'] = $this->get_SQL_where_from_query_opts(); // build up the ORDER BY clause if (isset($this->sfn)) { $sort_fields = array(); $sort_fields_w = array(); foreach ($this->sfn as $field) { if ($field[0] == '-') { $field = substr($field, 1); $desc = true; } else { $field = $field; $desc = false; } $sort_field = $this->fqn($field); $sort_field_w = $this->fdd[$field]['name']; $this->col_has_sql($field) && $sort_field_w .= ' (sql)'; if ($desc) { $sort_field .= ' DESC'; $sort_field_w .= ' '.$this->labels['descending']; } else { $sort_field_w .= ' '.$this->labels['ascending']; } $sort_fields[] = $sort_field; $sort_fields_w[] = $sort_field_w; } if (count($sort_fields) > 0) { $qparts['orderby'] = join(',', $sort_fields); } } $qparts['limit'] = $listall ? '' : $this->sql_limit($this->fm,$this->inc); $this->sort_fields_w = $sort_fields_w; // due to display sorting sequence return $qparts; } /* }}} */ function get_SQL_main_list_query($qparts) /* {{{ */ { return $this->get_SQL_query($qparts); } /* }}} */ function get_SQL_query($parts) /* {{{ */ { foreach ($parts as $k => $v) { $parts[$k] = trim($parts[$k]); } switch ($parts['type']) { case 'select': $ret = 'SELECT '; if ($parts['DISTINCT']) $ret .= 'DISTINCT '; $ret .= $parts['select']; $ret .= ' FROM '.$parts['from']; if ($parts['where'] != '') $ret .= ' WHERE '.$parts['where']; if ($parts['groupby'] != '') $ret .= ' GROUP BY '.$parts['groupby']; if ($parts['having'] != '') $ret .= ' HAVING '.$parts['having']; if ($parts['orderby'] != '') $ret .= ' ORDER BY '.$parts['orderby']; if ($parts['limit'] != '') $ret .= ' '.$parts['limit']; if ($parts['procedure'] != '') $ret .= ' PROCEDURE '.$parts['procedure']; break; case 'update': $ret = 'UPDATE '.$parts['table']; $ret .= ' SET '.$parts['fields']; if ($parts['where'] != '') $ret .= ' WHERE '.$parts['where']; break; case 'insert': $ret = 'INSERT INTO '.$parts['table']; $ret .= ' VALUES '.$parts['values']; break; case 'delete': $ret = 'DELETE FROM '.$parts['table']; if ($parts['where'] != '') $ret .= ' WHERE '.$parts['where']; break; default: die('unknown query type'); break; } return $ret; } /* }}} */ function get_SQL_column_list() /* {{{ */ { $fields = array(); for ($k = 0; $k < $this->num_fds; $k++) { if (! $this->displayed[$k] && $k != $this->key_num) { continue; } $fields[] = $this->fqn($k).' AS '.$this->sd.'qf'.$k.$this->ed; // no delimiters here, or maybe some yes if ($this->col_has_values($k)) { if($this->col_has_sql($k)) $fields[] = $this->fdd[$k]['sql'].' AS '.$this->sd.'qf'.$k.'_idx'.$this->ed; else $fields[] = $this->fqn($k, true, true).' AS '.$this->sd.'qf'.$k.'_idx'.$this->ed; } if ($this->col_has_datemask($k)) { $fields[] = 'UNIX_TIMESTAMP('.$this->fqn($k).') AS '.$this->sd.'qf'.$k.'_timestamp'.$this->ed; } } return join(',', $fields); } /* }}} */ function get_SQL_join_clause() /* {{{ */ { $main_table = $this->sd.'PMEtable0'.$this->ed; $join_clause = $this->sd.$this->tb.$this->ed." AS $main_table"; for ($k = 0, $numfds = sizeof($this->fds); $k < $numfds; $k++) { $main_column = $this->fds[$k]; if($this->fdd[$main_column]['values']['db']) { $dbp = $this->sd.$this->fdd[$main_column]['values']['db'].$this->ed.'.'; } else { //$dbp = $this->dbp; } $table = $this->sd.$this->fdd[$main_column]['values']['table'].$this->ed; $join_column = $this->sd.$this->fdd[$main_column]['values']['column'].$this->ed; $join_desc = $this->sd.$this->fdd[$main_column]['values']['description'].$this->ed; if ($join_desc != $this->sd.$this->ed && $join_column != $this->sd.$this->ed) { $join_table = $this->sd.'PMEjoin'.$k.$this->ed; $ar = array( 'main_table' => $main_table, 'main_column' => $this->sd.$main_column.$this->ed, 'join_table' => $join_table, 'join_column' => $join_column, 'join_description' => $join_desc); $join_clause .= " LEFT OUTER JOIN $dbp".$table." AS $join_table ON ("; $join_clause .= isset($this->fdd[$main_column]['values']['join']) ? $this->substituteVars($this->fdd[$main_column]['values']['join'], $ar) : "$join_table.$join_column = $main_table.".$this->sd.$main_column.$this->ed; $join_clause .= ')'; } } return $join_clause; } /* }}} */ function get_SQL_where_from_query_opts($qp = null, $text = 0) /* {{{ */ { if ($qp == null) { $qp = $this->query_opts; } $where = array(); foreach ($qp as $field => $ov) { if (is_numeric($field)) { $tmp_where = array(); foreach ($ov as $field2 => $ov2) { $tmp_where[] = sprintf('%s %s %s', $field2, $ov2['oper'], $ov2['value']); } $where[] = '('.join(' OR ', $tmp_where).')'; } else { if (is_array($ov['value'])) { $tmp_ov_val = ''; foreach ($ov['value'] as $ov_val) { strlen($tmp_ov_val) > 0 && $tmp_ov_val .= ' OR '; $tmp_ov_val .= sprintf('FIND_IN_SET("%s",%s)', $ov_val, $field); } $where[] = "($tmp_ov_val)"; } else { $where[] = sprintf('%s %s %s', $field, $ov['oper'], $ov['value']); } } } // Add any coder specified filters if (! $text && $this->filters) { $where[] = '('.$this->filters.')'; } if (count($where) > 0) { if ($text) { return str_replace('%', '*', join(' AND ',$where)); } else { return join(' AND ',$where); } } return ''; /* empty string */ } /* }}} */ function gather_query_opts() /* {{{ */ { $this->query_opts = array(); $this->prev_qfn = $this->qfn; $this->qfn = ''; if ($this->clear_operation()) { return; } // gathers query options into an array, $this->query_opts $qo = array(); for ($k = 0; $k < $this->num_fds; $k++) { $l = 'qf'.$k; $lc = 'qf'.$k.'_comp'; $li = 'qf'.$k.'_id'; $m = $this->get_sys_cgi_var($l); $mc = $this->get_sys_cgi_var($lc); $mi = $this->get_sys_cgi_var($li); if (! isset($m) && ! isset($mi)) { continue; } if (is_array($m) || is_array($mi)) { if (is_array($mi)) { $m = $mi; $l = $li; } if (in_array('*', $m)) { continue; } if ($this->col_has_values($k) && $this->col_has_multiple($k)) { foreach (array_keys($m) as $key) { $m[$key] = addslashes($m[$key]); } $qo[$this->fqn($k)] = array('value' => $m); } else { $qf_op = ''; foreach (array_keys($m) as $key) { if ($qf_op == '') { $qf_op = 'IN'; $qf_val = '"'.addslashes($m[$key]).'"'; $afilter = ' IN ("'.addslashes($m[$key]).'"'; // ) } else { $afilter = $afilter.',"'.addslashes($m[$key]).'"'; $qf_val .= ',"'.addslashes($m[$key]).'"'; } $this->qfn .= '&'.$this->cgi['prefix']['sys'].$l.'['.rawurlencode($key).']='.rawurlencode($m[$key]); } $afilter = $afilter.')'; // XXX: $dont_desc and $dont_cols hack $dont_desc = isset($this->fdd[$k]['values']['description']); $dont_cols = isset($this->fdd[$k]['values']['column']); $qo[$this->fqn($k, $dont_desc, $dont_cols)] = array('oper' => $qf_op, 'value' => "($qf_val)"); // ) } } else if (isset($mi)) { if ($mi == '*') { continue; } if ($this->fdd[$k]['select'] != 'M' && $this->fdd[$k]['select'] != 'D' && $mi == '') { continue; } $afilter = addslashes($mi); $qo[$this->fqn($k, true, true)] = array('oper' => '=', 'value' => "'$afilter'"); $this->qfn .= '&'.$this->cgi['prefix']['sys'].$li.'='.rawurlencode($mi); } else if (isset($m)) { if ($m == '*') { continue; } if ($this->fdd[$k]['select'] != 'M' && $this->fdd[$k]['select'] != 'D' && $m == '') { continue; } $afilter = addslashes($m); if ($this->fdd[$k]['select'] == 'N') { $mc = in_array($mc, $this->comp_ops) ? $mc : '='; $qo[$this->fqn($k)] = array('oper' => $mc, 'value' => "'$afilter'"); $this->qfn .= '&'.$this->cgi['prefix']['sys'].$l .'='.rawurlencode($m); $this->qfn .= '&'.$this->cgi['prefix']['sys'].$lc.'='.rawurlencode($mc); } else { $afilter = '%'.str_replace('*', '%', $afilter).'%'; $ids = array(); $ar = array(); $ar[$this->fqn($k)] = array('oper' => 'LIKE', 'value' => "'$afilter'"); if (is_array($this->fdd[$k]['values2'])) { foreach ($this->fdd[$k]['values2'] as $key => $val) { if (strlen($m) > 0 && stristr($val, $m)) { $ids[] = '"'.addslashes($key).'"'; } } if (count($ids) > 0) { $ar[$this->fqn($k, true, true)] = array('oper' => 'IN', 'value' => '('.join(',', $ids).')'); } } $qo[] = $ar; $this->qfn .= '&'.$this->cgi['prefix']['sys'].$l.'='.rawurlencode($m); } } } $this->query_opts = $qo; } /* }}} */ /* * Create JavaScripts */ function form_begin() /* {{{ */ { $page_name = htmlspecialchars($this->page_name); if ($this->add_operation() || $this->change_operation() || $this->copy_operation() || $this->view_operation() || $this->delete_operation()) { $field_to_tab = array(); for ($tab = $k = $this->cur_tab = 0; $k < $this->num_fds; $k++) { if (isset($this->fdd[$k]['tab'])) { if ($tab == 0 && $k > 0) { $this->tabs[0] = 'PMEtab0'; $this->cur_tab = 1; $tab++; } if (is_array($this->fdd[$k]['tab'])) { $this->tabs[$tab] = @$this->fdd[$k]['tab']['name']; $this->fdd[$k]['tab']['default'] && $this->cur_tab = $tab; } else { $this->tabs[$tab] = @$this->fdd[$k]['tab']; } $tab++; } $field_to_tab[$k] = max(0, $tab - 1); } if (preg_match('/^'.$this->dhtml['prefix'].'tab(\d+)$/', $this->get_sys_cgi_var('cur_tab'), $parts)) { $this->cur_tab = $parts[1]; } if ($this->tabs_enabled()) { // initial TAB styles echo '',"\n"; // TAB javascripts echo '', "\n"; } } if ($this->add_operation() || $this->change_operation() || $this->copy_operation()) { $first_required = true; for ($k = 0; $k < $this->num_fds; $k++) { if ($this->displayed[$k] && ! $this->readonly($k) && ! $this->hidden($k) && ($this->fdd[$k]['js']['required'] || isset($this->fdd[$k]['js']['regexp']))) { if ($first_required) { $first_required = false; echo '', "\n"; } } if ($this->filter_operation()) { echo '', "\n"; } if ($this->display['form']) { echo '
',"\n"; } return true; } /* }}} */ function form_end() /* {{{ */ { if ($this->display['form']) { echo '
',"\n"; } } /* }}} */ function display_tab_labels($position) /* {{{ */ { if (! is_array($this->tabs)) { return false; } echo '',"\n"; echo '',"\n"; for ($i = ($this->tabs[0] == 'PMEtab0' ? 1 : 0); $i < count($this->tabs); $i++) { $css_class_name = $this->getCSSclass($i != $this->cur_tab ? 'tab' : 'tab-selected', $position); echo '',"\n"; } echo '',"\n"; echo '',"\n"; echo '
'; echo ''; echo $this->tabs[$i],' 
',"\n"; } /* }}} */ /* * Display functions */ function display_add_record() /* {{{ */ { for ($tab = 0, $k = 0; $k < $this->num_fds; $k++) { if (isset($this->fdd[$k]['tab']) && $this->tabs_enabled() && $k > 0) { $tab++; echo '',"\n"; echo '',"\n"; echo '
',"\n"; echo '',"\n"; } if (! $this->displayed[$k]) { continue; } if ($this->hidden($k)) { echo $this->htmlHiddenData($this->fds[$k], $this->fdd[$k]['default']); continue; } $css_postfix = @$this->fdd[$k]['css']['postfix']; $css_class_name = $this->getCSSclass('input', null, 'next', $css_postfix); $escape = isset($this->fdd[$k]['escape']) ? $this->fdd[$k]['escape'] : true; echo '',"\n"; echo '',"\n"; echo '',"\n"; if ($this->guidance) { $css_class_name = $this->getCSSclass('help', null, true, $css_postfix); $cell_value = $this->fdd[$k]['help'] ? $this->fdd[$k]['help'] : ' '; echo '',"\n"; } echo '',"\n"; } } /* }}} */ function display_copy_change_delete_record() /* {{{ */ { /* * For delete or change: SQL SELECT to retrieve the selected record */ $qparts['type'] = 'select'; $qparts['select'] = $this->get_SQL_column_list(); $qparts['from'] = $this->get_SQL_join_clause(); $qparts['where'] = '('.$this->fqn($this->key).'=' .$this->key_delim.$this->rec.$this->key_delim.')'; $res = $this->myquery($this->get_SQL_query($qparts),__LINE__); if (! ($row = $this->sql_fetch($res))) { return false; } for ($tab = 0, $k = 0; $k < $this->num_fds; $k++) { if (isset($this->fdd[$k]['tab']) && $this->tabs_enabled() && $k > 0) { $tab++; echo '
'; echo $this->fdd[$k]['name'],'getColAttributes($k),">\n"; if ($this->col_has_values($k)) { $vals = $this->set_values($k); $selected = @$this->fdd[$k]['default']; $multiple = $this->col_has_multiple($k); $readonly = $this->readonly($k); $strip_tags = true; //$escape = true; if ($this->col_has_checkboxes($k) || $this->col_has_radio_buttons($k)) { echo $this->htmlRadioCheck($this->cgi['prefix']['data'].$this->fds[$k], $css_class_name, $vals, $selected, $multiple, $readonly, $strip_tags, $escape); } else { echo $this->htmlSelect($this->cgi['prefix']['data'].$this->fds[$k], $css_class_name, $vals, $selected, $multiple, $readonly, $strip_tags, $escape); } } elseif (isset ($this->fdd[$k]['textarea'])) { echo $this->htmlTextarea($this->cgi['prefix']['data'].$this->fds[$k], $css_class_name, $k, $this->fdd[$k]['default']); } elseif ($this->col_has_php($k)) { echo include($this->fdd[$k]['php']); } else { // Simple edit box required $len_props = ''; $maxlen = intval($this->fdd[$k]['maxlen']); $size = isset($this->fdd[$k]['size']) ? $this->fdd[$k]['size'] : min($maxlen, 60); if ($size > 0) { $len_props .= ' size="'.$size.'"'; } if ($maxlen > 0) { $len_props .= ' maxlength="'.$maxlen.'"'; } echo 'password($k) ? 'type="password"' : 'type="text"'); echo ($this->readonly($k) ? ' disabled' : ''); echo ' name="',$this->cgi['prefix']['data'].$this->fds[$k],'"'; echo $len_props,' value="'; if($escape) echo htmlspecialchars($this->fdd[$k]['default']); else echo $this->fdd[$k]['default']; echo '" />'; } echo '',$cell_value,'
',"\n"; echo '
',"\n"; echo '
',"\n"; echo '',"\n"; } if (! $this->displayed[$k]) { continue; } if ($this->copy_operation() || $this->change_operation()) { if ($this->hidden($k)) { if ($k != $this->key_num) { echo $this->htmlHiddenData($this->fds[$k], $row["qf$k"]); } continue; } $css_postfix = @$this->fdd[$k]['css']['postfix']; echo '',"\n"; echo '',"\n"; /* There are two possibilities of readonly fields handling: 1. Display plain text for readonly timestamps, dates and URLs. 2. Display disabled input field In all cases particular readonly field will NOT be saved. */ if ($this->readonly($k) && ($this->col_has_datemask($k) || $this->col_has_URL($k))) { echo $this->display_delete_field($row, $k); } elseif ($this->password($k)) { echo $this->display_password_field($row, $k); } else { echo $this->display_change_field($row, $k); } if ($this->guidance) { $css_class_name = $this->getCSSclass('help', null, true, $css_postfix); $cell_value = $this->fdd[$k]['help'] ? $this->fdd[$k]['help'] : ' '; echo '',"\n"; } echo '',"\n"; } elseif ($this->delete_operation() || $this->view_operation()) { $css_postfix = @$this->fdd[$k]['css']['postfix']; echo '',"\n"; echo '',"\n"; if ($this->password($k)) { echo '',"\n"; } else { $this->display_delete_field($row, $k); } if ($this->guidance) { $css_class_name = $this->getCSSclass('help', null, true, $css_postfix); $cell_value = $this->fdd[$k]['help'] ? $this->fdd[$k]['help'] : ' '; echo '',"\n"; } echo '',"\n"; } } } /* }}} */ function display_change_field($row, $k) /* {{{ */ { $css_postfix = @$this->fdd[$k]['css']['postfix']; $css_class_name = $this->getCSSclass('input', null, true, $css_postfix); $escape = isset($this->fdd[$k]['escape']) ? $this->fdd[$k]['escape'] : true; echo '',"\n"; } /* }}} */ function display_password_field($row, $k) /* {{{ */ { $css_postfix = @$this->fdd[$k]['css']['postfix']; echo '',"\n"; } /* }}} */ function display_delete_field($row, $k) /* {{{ */ { $css_postfix = @$this->fdd[$k]['css']['postfix']; $css_class_name = $this->getCSSclass('value', null, true, $css_postfix); echo '',"\n"; } /* }}} */ /** * Returns CSS class name */ function getCSSclass($name, $position = null, $divider = null, $postfix = null) /* {{{ */ { static $div_idx = -1; $elements = array($this->css['prefix'], $name); if ($this->page_type && $this->css['page_type']) { if ($this->page_type != 'L' && $this->page_type != 'F') { $elements[] = $this->page_types[$this->page_type]; } } if ($position && $this->css['position']) { $elements[] = $position; } if ($divider && $this->css['divider']) { if ($divider === 'next') { $div_idx++; if ($this->css['divider'] > 0 && $div_idx >= $this->css['divider']) { $div_idx = 0; } } $elements[] = $div_idx; } if ($postfix) { $elements[] = $postfix; } return join($this->css['separator'], $elements); } /* }}} */ /** * Returns field cell HTML attributes */ function getColAttributes($k) /* {{{ */ { $colattrs = ''; if (isset($this->fdd[$k]['colattrs'])) { $colattrs .= ' '; $colattrs .= trim($this->fdd[$k]['colattrs']); } if (isset($this->fdd[$k]['nowrap'])) { $colattrs .= ' nowrap'; } return $colattrs; } /* }}} */ /** * Substitutes variables in string * (this is very simple but secure eval() replacement) */ function substituteVars($str, $subst_ar) /* {{{ */ { $array = preg_split('/(\\$\w+)/', $str, -1, PREG_SPLIT_DELIM_CAPTURE); $count = count($array); for ($i = 1; $i < $count; $i += 2) { $key = substr($array[$i], 1); if (isset($subst_ar[$key])) { $array[$i] = $subst_ar[$key]; } } return join('', $array); } /* }}} */ /** * Print URL */ function urlDisplay($k, $link_val, $disp_val, $css, $key) /* {{{ */ { $escape = isset($this->fdd[$k]['escape']) ? $this->fdd[$k]['escape'] : true; $ret = ''; $name = $this->fds[$k]; $page = $this->page_name; $url = $this->cgi['prefix']['sys'].'rec'.'='.$key.'&'.$this->cgi['prefix']['sys'].'fm' .'='.$this->fm.'&'.$this->cgi['prefix']['sys'].'fl'.'='.$this->fl; $url .= '&'.$this->cgi['prefix']['sys'].'qfn'.'='.rawurlencode($this->qfn).$this->qfn; $url .= '&'.$this->get_sfn_cgi_vars().$this->cgi['persist']; $ar = array( 'key' => $key, 'name' => $name, 'link' => $link_val, 'value' => $disp_val, 'css' => $css, 'page' => $page, 'url' => $url ); $urllink = isset($this->fdd[$k]['URL']) ? $this->substituteVars($this->fdd[$k]['URL'], $ar) : $link_val; $urldisp = isset($this->fdd[$k]['URLdisp']) ? $this->substituteVars($this->fdd[$k]['URLdisp'], $ar) : $disp_val; $target = isset($this->fdd[$k]['URLtarget']) ? 'target="'.htmlspecialchars($this->fdd[$k]['URLtarget']).'" ' : ''; $prefix_found = false; $postfix_found = false; $prefix_ar = @$this->fdd[$k]['URLprefix']; $postfix_ar = @$this->fdd[$k]['URLpostfix']; is_array($prefix_ar) || $prefix_ar = array($prefix_ar); is_array($postfix_ar) || $postfix_ar = array($postfix_ar); foreach ($prefix_ar as $prefix) { if (! strncmp($prefix, $urllink, strlen($prefix))) { $prefix_found = true; break; } } foreach ($postfix_ar as $postfix) { if (! strncmp($postfix, $urllink, strlen($postfix))) { $postfix_found = true; break; } } $prefix_found || $urllink = array_shift($prefix_ar).$urllink; $postfix_found || $urllink = $urllink.array_shift($postfix_ar); if (strlen($urllink) <= 0 || strlen($urldisp) <= 0) { $ret = ' '; } else { if ($escape) { $urldisp = htmlspecialchars($urldisp); } $urllink = htmlspecialchars($urllink); $ret = ''.$urldisp.''; } return $ret; } /* }}} */ function cellDisplay($k, $row, $css) /* {{{ */ { $escape = isset($this->fdd[$k]['escape']) ? $this->fdd[$k]['escape'] : true; $key_rec = $row['qf'.$this->key_num]; if (@$this->fdd[$k]['datemask']) { $value = intval($row["qf$k".'_timestamp']); $value = $value ? @date($this->fdd[$k]['datemask'], $value) : ''; } else if (@$this->fdd[$k]['strftimemask']) { $value = intval($row["qf$k".'_timestamp']); $value = $value ? @strftime($this->fdd[$k]['strftimemask'], $value) : ''; } else if ($this->is_values2($k, $row["qf$k"])) { $value = $row['qf'.$k.'_idx']; if ($this->fdd[$k]['select'] == 'M') { $value_ar = explode(',', $value); $value_ar2 = array(); foreach ($value_ar as $value_key) { if (isset($this->fdd[$k]['values2'][$value_key])) { $value_ar2[$value_key] = $this->fdd[$k]['values2'][$value_key]; $escape = false; } } $value = join(', ', $value_ar2); } else { if (isset($this->fdd[$k]['values2'][$value])) { $value = $this->fdd[$k]['values2'][$value]; $escape = false; } } } elseif (isset($this->fdd[$k]['values2'][$row["qf$k"]])) { $value = $this->fdd[$k]['values2'][$row["qf$k"]]; } else { $value = $row["qf$k"]; } $original_value = $value; if (@$this->fdd[$k]['strip_tags']) { $value = strip_tags($value); } if ($num_ar = @$this->fdd[$k]['number_format']) { if (! is_array($num_ar)) { $num_ar = array($num_ar); } if (count($num_ar) == 1) { list($nbDec) = $num_ar; $value = number_format($value, $nbDec); } else if (count($num_ar) == 3) { list($nbDec, $decPoint, $thSep) = $num_ar; $value = number_format($value, $nbDec, $decPoint, $thSep); } } if (intval($this->fdd[$k]['trimlen']) > 0 && strlen($value) > $this->fdd[$k]['trimlen']) { $value = ereg_replace("[\r\n\t ]+",' ',$value); $value = substr($value, 0, $this->fdd[$k]['trimlen'] - 3).'...'; } if (@$this->fdd[$k]['mask']) { $value = sprintf($this->fdd[$k]['mask'], $value); } if ($this->col_has_php($k)) { return include($this->fdd[$k]['php']); } if ($this->col_has_URL($k)) { return $this->urlDisplay($k, $original_value, $value, $css, $key_rec); } if (strlen($value) <= 0) { return ' '; } if ($escape) { $value = htmlspecialchars($value); } return nl2br($value); } /* }}} */ /** * Creates HTML submit input element * * @param name element name * @param label key in the language hash used as label * @param css_class_name CSS class name * @param js_validation if add JavaScript validation subroutine to button * @param disabled if mark the button as disabled * @param js any extra text in tags */ function htmlSubmit($name, $label, $css_class_name, $js_validation = true, $disabled = false, $js = NULL) /* {{{ */ { // Note that isn't valid HTML, but most browsers support it if($disabled == -1) return; $markdisabled = $disabled ? ' disabled' : ''; $ret = '
'; echo $this->fdd[$k]['name'],'',$cell_value,'
'; echo $this->fdd[$k]['name'],'getColAttributes($k),'>',$this->labels['hidden'],'',$cell_value,'
getColAttributes($k),">\n"; if ($this->col_has_values($k)) { $vals = $this->set_values($k); $multiple = $this->col_has_multiple($k); $readonly = $this->readonly($k); $strip_tags = true; //$escape = true; if ($this->col_has_checkboxes($k) || $this->col_has_radio_buttons($k)) { echo $this->htmlRadioCheck($this->cgi['prefix']['data'].$this->fds[$k], $css_class_name, $vals, $row["qf$k"], $multiple, $readonly, $strip_tags, $escape); } else { echo $this->htmlSelect($this->cgi['prefix']['data'].$this->fds[$k], $css_class_name, $vals, $row["qf$k"], $multiple, $readonly, $strip_tags, $escape); } } elseif (isset($this->fdd[$k]['textarea'])) { echo $this->htmlTextarea($this->cgi['prefix']['data'].$this->fds[$k], $css_class_name, $k, $row["qf$k"]); } elseif ($this->col_has_php($k)) { echo include($this->fdd[$k]['php']); } else { $len_props = ''; $maxlen = intval($this->fdd[$k]['maxlen']); $size = isset($this->fdd[$k]['size']) ? $this->fdd[$k]['size'] : min($maxlen, 60); if ($size > 0) { $len_props .= ' size="'.$size.'"'; } if ($maxlen > 0) { $len_props .= ' maxlength="'.$maxlen.'"'; } echo 'readonly($k) ? ' disabled' : ''); echo ' name="',$this->cgi['prefix']['data'].$this->fds[$k],'" value="'; if($escape) echo htmlspecialchars($row["qf$k"]); else echo $row["qf$k"]; echo '"',$len_props,' />',"\n"; } echo 'getColAttributes($k),">\n"; $len_props = ''; $maxlen = intval($this->fdd[$k]['maxlen']); $size = isset($this->fdd[$k]['size']) ? $this->fdd[$k]['size'] : min($maxlen, 60); if ($size > 0) { $len_props .= ' size="'.$size.'"'; } if ($maxlen > 0) { $len_props .= ' maxlength="'.$maxlen.'"'; } echo 'readonly($k) ? ' disabled' : ''); echo ' name="',$this->cgi['prefix']['data'].$this->fds[$k],'" value="'; echo htmlspecialchars($row["qf$k"]),'"',$len_props,' />',"\n"; echo 'getColAttributes($k),">\n"; echo $this->cellDisplay($k, $row, $css_class_name); echo '
',"\n"; echo '',"\n"; echo '',"\n"; // Message is now written here if (strlen(@$this->message) > 0) { echo '',"\n"; } if($this->display['num_pages'] || $this->display['num_records']) echo ''; echo '
',"\n"; echo $but_str,'',$this->message,'',"\n"; if($this->display['num_pages']) { if ($listall) { echo $this->labels['Page'],': 1 ',$this->labels['of'],' 1'; } else { $current_page = intval($this->fm / $this->inc) + 1; $total_pages = max(1, ceil($this->total_recs / abs($this->inc))); echo $this->labels['Page'],': ',$current_page; echo ' ',$this->labels['of'],' ',$total_pages; } } if($this->display['num_records']) echo '  ',$this->labels['Records'],': ',$this->total_recs; if($this->display['num_pages'] || $this->display['num_records']) echo '
',"\n"; if($position == 'up') echo '
'."\n"; } /* }}} */ /* * Display buttons at top and bottom of page */ function display_record_buttons($position) /* {{{ */ { if (($but_str = $this->display_buttons($position)) === null) return; if ($position == 'down') { if ($this->tabs_enabled()) $this->display_tab_labels('down'); echo '
',"\n"; } echo '',"\n"; echo '',"\n"; echo '',"\n"; // Message is now written here //echo '',"\n"; if (strlen(@$this->message) > 0) { echo '',"\n"; } echo '
',"\n"; echo $but_str,'',$this->message,'
',"\n"; if ($position == 'up') { if ($this->tabs_enabled()) $this->display_tab_labels('up'); echo '
',"\n"; } } /* }}} */ function display_buttons($position) /* {{{ */ { $nav_fnc = 'nav_'.$position; if(! $this->$nav_fnc()) return; $buttons = (is_array($this->buttons[$this->page_type][$position])) ? $this->buttons[$this->page_type][$position] : $this->default_buttons[$this->page_type]; foreach ($buttons as $name) { $ret .= $this->display_button($name, $position)."\n"; } return $ret; } /* }}} */ function display_button($name, $position = 'up') /* {{{ */ { if (is_array($name)) { if (isset($name['code'])) return $name['code']; return $this->htmlSubmit($name['name'], $name['value'], $name['css'], $name['js_validation'], $name['disabled'], $name['js']); } $disabled = 1; // show disabled by default if ($name[0] == '+') { $name = substr($name, 1); $disabled = 0; } // always show disabled as enabled if ($name[0] == '-') { $name = substr($name, 1); $disabled = -1; } // don't show disabled if ($name == 'cancel') { return $this->htmlSubmit('cancel'.$this->page_types[$this->page_type], 'Cancel', $this->getCSSclass('cancel', $position), false); } if (in_array($name, array('add','view','change','copy','delete'))) { $enabled_fnc = $name.'_enabled'; $enabled = $this->$enabled_fnc(); if ($name != 'add' && ! $this->total_recs && strstr('LF', $this->page_type)) $enabled = false; return $this->htmlSubmit('operation', ucfirst($name), $this->getCSSclass($name, $position), false, $enabled ? 0 : $disabled); } if ($name == 'savedelete') { $enabled = $this->delete_enabled(); $js = 'onclick="return confirm(\''.$this->labels['Delete'].' ?\');"'; return $this->htmlSubmit('savedelete', 'Delete', $this->getCSSclass('save', $position), false, $enabled ? 0 : $disabled, $js); } if (in_array($name, array('save','more'))) { $validation = true; // if js validation if ($this->page_type == 'D' && $name == 'save' ) { $value = 'Delete'; $validation = false; } elseif ($this->page_type == 'C' && $name == 'more' ) { $value = 'Apply'; } else $value = ucfirst($name); return $this->htmlSubmit($name.$this->page_types[$this->page_type], $value, $this->getCSSclass($name, $position), $validation); } $listall = $this->inc <= 0; if ($listall) { $disabledprev = true; $disablednext = true; $total_pages = 1; $current_page = 1; } else { $disabledprev = $this->fm <= 0; $disablednext = $this->fm + $this->inc >= $this->total_recs; $total_pages = max(1, ceil($this->total_recs / abs($this->inc))); $current_page = ceil($this->fm / abs($this->inc)); // must + 1 } $disabledfirst = $disabledprev; $disabledlast = $disablednext; // some statistics first if ($name == 'total_pages') return $total_pages; if ($name == 'current_page') return ($current_page+1); if ($name == 'total_recs') return ($this->total_recs); // now some goto buttons/dropdowns/inputs... if ($name == 'goto_text') { $ret = 'cgi['prefix']['sys'].'navpn'.$position.'" value="'.($current_page+1).'"'; $ret .= ' size="'.(strlen($total_pages)+1).'" maxlength="'.(strlen($total_pages)+1).'"'; // TODO some js here.... on enter submit, on click erase ?... $ret .=' oneypress="return PE_filter_handler(this.form, event);" />'; return $ret; } if ($name == 'goto_combo') { $disabledgoto = !($listall || ($disablednext && $disabledprev)) ? '' : ' disabled'; if ($disablegoto != '' && $disabled < 0) return; $kv_array = array(); for ($i = 0; $i < $total_pages; $i++) { $kv_array[$this->inc * $i] = $i + 1; } // TODO: add onchange="return this.form.submit();" DONE ??? return $this->htmlSelect($this->cgi['prefix']['sys'].ltrim($disabledgoto).'navfm'.$position, $this->getCSSclass('goto', $position), $kv_array, (string)$this->fm, false, $disabledgoto, false, true, 'onchange="return this.form.submit();"'); } if ($name == 'goto') { return $this->htmlSubmit('navop', 'Go to', $this->getCSSclass('goto', $position), false, ($listall || ($disablednext && $disabledprev)) ? $disabled : 0); } if (in_array($name, array('first','prev','next','last','<<','<','>','>>'))) { $disabled_var = 'disabled'.$name; $name2 = $name; if (strlen($name) <= 2) { $nav_values = array('<<' => 'first', '<' => 'prev', '>' => 'next', '>>' => 'last'); $disabled_var = 'disabled'.$nav_values[$name]; $name2 = $nav_values[$name]; } return $this->htmlSubmit('navop', ucfirst($name), $this->getCSSclass($name2, $position), false, $$disabled_var ? $disabled : 0); } if(isset($this->labels[$name])) return $this->labels[$name]; return $name; } /* }}} */ function number_of_recs() /* {{{ */ { $count_parts = array( 'type' => 'select', 'select' => 'count(*)', 'from' => $this->get_SQL_join_clause(), 'where' => $this->get_SQL_where_from_query_opts()); $res = $this->myquery($this->get_SQL_main_list_query($count_parts), __LINE__); $row = $this->sql_fetch($res, 'n'); $this->total_recs = $row[0]; } /* }}} */ function filter_heading() /* {{{ */ { /* FILTER {{{ * * Draw the filter and fill it with any data typed in last pass and stored * in the array parameter keyword 'filter'. Prepare the SQL WHERE clause. */ // Filter row retrieval /*$fields = false; $filter_row = array();//$row; if (! is_array($filter_row)) { echo 'tttt'; unset($qparts['where']); $query = $this->get_SQL_query($qparts); $res = $this->myquery($query, __LINE__); if ($res == false) { $this->error('invalid SQL query', $query); return false; } $filter_row = $this->sql_fetch($res); }*/ /* TODO - $fields is completely useless (michal) Variable $fields is used to get index of particular field in result. That index can be passed in example to $this->sql_field_len() function. Use field names as indexes to $fields array. */ if (is_array($filter_row)) { $fields = array_flip(array_keys($filter_row)); } //if ($fields != false) { $css_class_name = $this->getCSSclass('filter'); echo '',"\n"; echo ''; echo $this->htmlSubmit('filter', 'Query', $this->getCSSclass('query'), false); echo '', "\n"; for ($k = 0; $k < $this->num_fds; $k++) { if (! $this->displayed[$k]) { continue; } $css_postfix = @$this->fdd[$k]['css']['postfix']; $css_class_name = $this->getCSSclass('filter', null, null, $css_postfix); $this->field_name = $this->fds[$k]; $fd = $this->field_name; $this->field = $this->fdd[$fd]; $l = 'qf'.$k; $lc = 'qf'.$k.'_comp'; $li = 'qf'.$k.'_id'; if ($this->clear_operation()) { $m = null; $mc = null; $mi = null; } else { $m = $this->get_sys_cgi_var($l); $mc = $this->get_sys_cgi_var($lc); $mi = $this->get_sys_cgi_var($li); } echo ''; if ($this->password($k)) { echo ' '; } else if ($this->fdd[$fd]['select'] == 'D' || $this->fdd[$fd]['select'] == 'M') { // Multiple fields processing // Default size is 2 and array required for values. $from_table = ! $this->col_has_values($k) || isset($this->fdd[$k]['values']['table']); $vals = $this->set_values($k, array('*' => '*'), null, $from_table); $selected = $mi; $multiple = $this->col_has_multiple_select($k); $multiple |= $this->fdd[$fd]['select'] == 'M'; $readonly = false; $strip_tags = true; $escape = true; echo $this->htmlSelect($this->cgi['prefix']['sys'].$l.'_id', $css_class_name, $vals, $selected, $multiple, $readonly, $strip_tags, $escape); } elseif ($this->fdd[$fd]['select'] == 'N' || $this->fdd[$fd]['select'] == 'T') { $len_props = ''; $maxlen = intval($this->fdd[$k]['maxlen']); //$maxlen > 0 || $maxlen = intval($this->sql_field_len($res, $fields["qf$k"])); $maxlen > 0 || $maxlen = 500; $size = isset($this->fdd[$k]['size']) ? $this->fdd[$k]['size'] : ($maxlen < 30 ? min($maxlen, 8) : 12); $len_props .= ' size="'.$size.'"'; $len_props .= ' maxlength="'.$maxlen.'"'; if ($this->fdd[$fd]['select'] == 'N') { $mc = in_array($mc, $this->comp_ops) ? $mc : '='; echo $this->htmlSelect($this->cgi['prefix']['sys'].$l.'_comp', $css_class_name, $this->comp_ops, $mc); } echo ''; } else { echo ' '; } echo '',"\n"; } echo '',"\n"; //} } /* }}} */ function display_sorting_sequence() /* {{{ */ { /* * Display sorting sequence */ $css_class_name = $this->getCSSclass('sortinfo'); echo '',"\n"; echo ''; echo '',$this->labels['Clear'],'',"\n"; echo ''; echo $this->labels['Sorted By'],': ',join(', ', $this->sort_fields_w),'',"\n"; } /* }}} */ function display_current_query() /* {{{ */ { /* * Display the current query */ $text_query = $this->get_SQL_where_from_query_opts(null, true); if ($text_query != '') { $css_class_name = $this->getCSSclass('queryinfo'); echo '',"\n"; echo ''; echo '',$this->labels['Clear'],'',"\n"; echo ''; echo $this->labels['Current Query'],': ',htmlspecialchars($text_query),'',"\n"; } } /* }}} */ /* * Table Page Listing */ function list_table() /* {{{ */ { if ($this->fm == '') { $this->fm = 0; } $this->fm = $this->navfm; if ($this->prev_operation()) { $this->fm = $this->fm - $this->inc; if ($this->fm < 0) { $this->fm = 0; } } if ($this->first_operation()) { $this->fm = 0; } // last operation must be performed below, after retrieving total_recs if ($this->next_operation()) { $this->fm += $this->inc; } $this->number_of_recs(); if ($this->last_operation() || $this->fm > $this->total_recs) { // if goto_text is badly set $this->fm = (int)(($this->total_recs - 1)/$this->inc)*$this->inc; } // If sort sequence has changed, restart listing $this->qfn != $this->prev_qfn && $this->fm = 0; if (0) { // DEBUG echo 'qfn vs. prev_qfn comparsion '; echo '[',htmlspecialchars($this->qfn),']'; echo '[',htmlspecialchars($this->prev_qfn),']
'; echo 'comparsion ',($this->qfn == $this->prev_qfn ? 'proved' : 'failed'),''; echo '
'; } /* * If user is allowed to Change/Delete records, we need an extra column * to allow users to select a record */ $select_recs = $this->key != '' && ($this->change_enabled() || $this->delete_enabled() || $this->view_enabled()); // Are we doing a listall? $listall = $this->inc <= 0; /* * Display the SQL table in an HTML table */ $this->form_begin(); echo $this->get_origvars_html($this->get_sfn_cgi_vars()); echo $this->htmlHiddenSys('fl', $this->fl); // Display buttons at top and/or bottom of page. $this->display_list_table_buttons('up', $listall); if ($this->cgi['persist'] != '') { echo $this->get_origvars_html($this->cgi['persist']); } if (! $this->filter_operation()) { echo $this->get_origvars_html($this->qfn); } echo $this->htmlHiddenSys('qfn', $this->qfn); echo $this->htmlHiddenSys('fm', $this->fm); echo '',"\n"; echo '',"\n"; /* * System (navigation, selection) columns counting */ $this->sys_cols = 0; $this->sys_cols += intval($this->filter_enabled() || $select_recs); if ($this->sys_cols > 0) { $this->sys_cols += intval($this->nav_buttons() && ($this->nav_text_links() || $this->nav_graphic_links())); } /* * We need an initial column(s) (sys columns) * if we have filters, Changes or Deletes enabled */ if ($this->sys_cols) { echo '',"\n"; } for ($k = 0; $k < $this->num_fds; $k++) { $fd = $this->fds[$k]; if (! $this->displayed[$k]) { continue; } $css_postfix = @$this->fdd[$k]['css']['postfix']; $css_class_name = $this->getCSSclass('header', null, null, $css_postfix); $fdn = $this->fdd[$fd]['name']; if (! $this->fdd[$fd]['sort'] || $this->password($fd)) { echo '',"\n"; } else { // Clicking on the current sort field reverses the sort order $new_sfn = $this->sfn; array_unshift($new_sfn, in_array("$k", $new_sfn, 1) ? "-$k" : $k); echo '',"\n"; } } echo '',"\n"; /* * Main list_table() query * * Each row of the HTML table is one record from the SQL query. We must * perform this query before filter printing, because we want to use * $this->sql_field_len() function. We will also fetch the first row to get * the field names. */ $qparts = $this->get_SQL_main_list_query_parts(); $query = $this->get_SQL_main_list_query($qparts); $res = $this->myquery($query, __LINE__); if ($res == false) { $this->error('invalid SQL query', $query); return false; } $row = $this->sql_fetch($res); // filter if ($this->filter_operation()) $this->filter_heading(); // Display sorting sequence if ($qparts['orderby'] && $this->display['sort']) $this->display_sorting_sequence(); // Display the current query if($this->display['query']) $this->display_current_query(); if ($this->nav_text_links() || $this->nav_graphic_links()) { $qstrparts = array(); strlen($this->fl) > 0 && $qstrparts[] = $this->cgi['prefix']['sys'].'fl'.'='.$this->fl; strlen($this->fm) > 0 && $qstrparts[] = $this->cgi['prefix']['sys'].'fm'.'='.$this->fm; count($this->sfn) > 0 && $qstrparts[] = $this->get_sfn_cgi_vars(); strlen($this->cgi['persist']) > 0 && $qstrparts[] = $this->cgi['persist']; $qpview = $qstrparts; $qpcopy = $qstrparts; $qpchange = $qstrparts; $qpdelete = $qstrparts; $qp_prefix = $this->cgi['prefix']['sys'].'operation'.'='.$this->cgi['prefix']['operation']; $qpview[] = $qp_prefix.'View'; $qpcopy[] = $qp_prefix.'Copy'; $qpchange[] = $qp_prefix.'Change'; $qpdelete[] = $qp_prefix.'Delete'; $qpviewStr = htmlspecialchars($this->page_name.'?'.join('&',$qpview).$this->qfn); $qpcopyStr = htmlspecialchars($this->page_name.'?'.join('&',$qpcopy).$this->qfn); $qpchangeStr = htmlspecialchars($this->page_name.'?'.join('&',$qpchange).$this->qfn); $qpdeleteStr = htmlspecialchars($this->page_name.'?'.join('&',$qpdelete).$this->qfn); } $fetched = true; $first = true; $rowCount = 0; while ((!$fetched && ($row = $this->sql_fetch($res)) != false) || ($fetched && $row != false)) { $fetched = false; echo '',"\n"; if ($this->sys_cols) { /* {{{ */ $key_rec = $row['qf'.$this->key_num]; $queryAppend = htmlspecialchars('&'.$this->cgi['prefix']['sys'].'rec'.'='.$key_rec); $viewQuery = $qpviewStr . $queryAppend; $copyQuery = $qpcopyStr . $queryAppend; $changeQuery = $qpchangeStr . $queryAppend; $deleteQuery = $qpdeleteStr . $queryAppend; $viewTitle = htmlspecialchars($this->labels['View']); $changeTitle = htmlspecialchars($this->labels['Change']); $copyTitle = htmlspecialchars($this->labels['Copy']); $deleteTitle = htmlspecialchars($this->labels['Delete']); $css_class_name = $this->getCSSclass('navigation', null, true); if ($select_recs) { if (! $this->nav_buttons() || $this->sys_cols > 1) { echo '',"\n"; } if ($this->nav_buttons()) { echo '',"\n"; } } elseif ($this->filter_enabled()) { echo '',"\n"; } } /* }}} */ for ($k = 0; $k < $this->num_fds; $k++) { /* {{{ */ $fd = $this->fds[$k]; if (! $this->displayed[$k]) { continue; } $css_postfix = @$this->fdd[$k]['css']['postfix']; $css_class_name = $this->getCSSclass('cell', null, true, $css_postfix); if ($this->password($k)) { echo '',"\n"; continue; } echo '',"\n"; } /* }}} */ echo '',"\n"; } /* * Display and accumulate column aggregation info, do totalling query * XXX this feature does not work yet!!! */ // aggregates listing (if any) if ($$var_to_total) { // do the aggregate query if necessary //if ($vars_to_total) { $qp = array(); $qp['type'] = 'select'; $qp['select'] = $aggr_from_clause; $qp['from'] = $this->get_SQL_join_clause(); $qp['where'] = $this->get_SQL_where_from_query_opts(); $tot_query = $this->get_SQL_query($qp); $totals_result = $this->myquery($tot_query,__LINE__); $tot_row = $this->sql_fetch($totals_result); //} $qp_aggr = $qp; echo "\n",'',"\n",'',"\n"; /* echo ''; echo ''; */ // display the results for ($k=0;$k<$this->num_fds;$k++) { $fd = $this->fds[$k]; if (stristr($this->fdd[$fd]['options'],'L') or !isset($this->fdd[$fd]['options'])) { echo '',"\n"; } } echo '',"\n"; } echo '
'; if ($this->filter_enabled()) { if ($this->filter_operation()) { echo $this->htmlSubmit('sw', 'Hide', $this->getCSSclass('hide'), false); echo $this->htmlSubmit('sw', 'Clear', $this->getCSSclass('clear'), false); } else { echo $this->htmlSubmit('sw', 'Search', $this->getCSSclass('search'), false); } } else { echo ' '; } echo '',$fdn,''; echo '',$fdn,'
'; } if ($this->nav_graphic_links()) { $printed_out = false; if ($this->view_enabled()) { $printed_out = true; echo ''; } if ($this->change_enabled()) { $printed_out && print(' '); $printed_out = true; echo ''; } if ($this->copy_enabled()) { $printed_out && print(' '); $printed_out = true; echo ''; } if ($this->delete_enabled()) { $printed_out && print(' '); $printed_out = true; echo ''; } } if ($this->nav_text_links()) { if ($this->nav_graphic_links()) { echo '
'; } $printed_out = false; if ($this->view_enabled()) { $printed_out = true; echo 'V'; } if ($this->change_enabled()) { $printed_out && print(' '); $printed_out = true; echo 'C'; } if ($this->copy_enabled()) { $printed_out && print(' '); $printed_out = true; echo 'P'; } if ($this->delete_enabled()) { $printed_out && print(' '); $printed_out = true; echo 'D'; } } if (! $this->nav_buttons() || $this->sys_cols > 1) { echo '
rec == '' && $first) || ($this->rec == $key_rec)) { echo ' checked'; $first = false; } echo ' /> ',$this->labels['hidden'],'getColAttributes($fd),'>'; echo $this->cellDisplay($k, $row, $css_class_name); echo '
 '; echo printarray($qp_aggr); echo printarray($vars_to_total); echo ''.$var_to_total.' '.$$var_to_total.''; $aggr_var = 'qf'.$k.'_aggr'; $$aggr_var = $this->get_sys_cgi_var($aggr_var); if ($$aggr_var) { echo $this->sql_aggrs[$$aggr_var],': ',$tot_row[$aggr_var]; } else { echo ' '; } echo '
',"\n"; // end of table rows listing $this->display_list_table_buttons('down', $listall); $this->form_end(); } /* }}} */ function display_record() /* {{{ */ { // PRE Triggers $ret = true; if ($this->change_operation()) { $ret &= $this->exec_triggers_simple('update', 'pre'); // if PRE update fails, then back to view operation if (! $ret) { $this->operation = $this->labels['View']; $ret = true; } } if ($this->add_operation() || $this->copy_operation()) { $ret &= $this->exec_triggers_simple('insert', 'pre'); } if ($this->view_operation()) { $ret &= $this->exec_triggers_simple('select', 'pre'); } if ($this->delete_operation()) { $ret &= $this->exec_triggers_simple('delete', 'pre'); } // if PRE insert/view/delete fail, then back to the list if ($ret == false) { $this->operation = ''; $this->list_table(); return; } $this->form_begin(); if ($this->cgi['persist'] != '') { echo $this->get_origvars_html($this->cgi['persist']); } echo $this->get_origvars_html($this->get_sfn_cgi_vars()); echo $this->get_origvars_html($this->qfn); echo $this->htmlHiddenSys('cur_tab', $this->dhtml['prefix'].'tab'.$this->cur_tab); echo $this->htmlHiddenSys('qfn', $this->qfn); echo $this->htmlHiddenSys('rec', $this->copy_operation() ? '' : $this->rec); echo $this->htmlHiddenSys('fm', $this->fm); echo $this->htmlHiddenSys('fl', $this->fl); $this->display_record_buttons('up'); if ($this->tabs_enabled()) { echo '
',"\n"; } echo '',"\n"; if ($this->add_operation()) { $this->display_add_record(); } else { $this->display_copy_change_delete_record(); } echo '
',"\n"; if ($this->tabs_enabled()) { echo '
',"\n"; } $this->display_record_buttons('down'); $this->form_end(); } /* }}} */ /* * Action functions */ function do_add_record() /* {{{ */ { // Preparing query $query = ''; $key_col_val = ''; $newvals = array(); for ($k = 0; $k < $this->num_fds; $k++) { if ($this->processed($k)) { $fd = $this->fds[$k]; if ($this->readonly($k)) { $fn = (string) @$this->fdd[$k]['default']; } else { $fn = $this->get_data_cgi_var($fd); } if ($fd == $this->key) { $key_col_val = $fn; } $newvals[$fd] = is_array($fn) ? join(',',$fn) : $fn; } } // Creating array of changed keys ($changed) $changed = array_keys($newvals); // Before trigger, newvals can be efectively changed if ($this->exec_triggers('insert', 'before', $oldvals, $changed, $newvals) == false) { return false; } // Real query (no additional query in this method) foreach ($newvals as $fd => $val) { if ($fd == '') continue; if ($this->col_has_sqlw($this->fdn[$fd])) { $val_as = addslashes($val); $val_qas = '"'.addslashes($val).'"'; $value = $this->substituteVars( $this->fdd[$this->fdn[$fd]]['sqlw'], array( 'val_qas' => $val_qas, 'val_as' => $val_as, 'val' => $val )); } else { $value = "'".addslashes($val)."'"; } if ($query == '') { $query = 'INSERT INTO '.$this->sd.$this->tb.$this->ed.' ('.$this->sd.$fd.$this->ed.''; // ) $query2 = ') VALUES ('.$value.''; } else { $query .= ', '.$this->sd.$fd.$this->ed.''; $query2 .= ', '.$value.''; } } $query .= $query2.')'; $res = $this->myquery($query, __LINE__); $this->message = $this->sql_affected_rows($this->dbh).' '.$this->labels['record added']; if (! $res) { return false; } $this->rec = $this->sql_insert_id(); // Notify list if (@$this->notify['insert'] || @$this->notify['all']) { $this->email_notify(false, $newvals); } // Note change in log table if ($this->logtable) { $query = sprintf('INSERT INTO %s' .' (updated, user, host, operation, tab, rowkey, col, oldval, newval)' .' VALUES (NOW(), "%s", "%s", "insert", "%s", "%s", "", "", "%s")', $this->logtable, addslashes($this->get_server_var('REMOTE_USER')), addslashes($this->get_server_var('REMOTE_ADDR')), addslashes($this->tb), addslashes($key_col_val), addslashes(serialize($newvals))); $this->myquery($query, __LINE__); } // After trigger if ($this->exec_triggers('insert', 'after', $oldvals, $changed, $newvals) == false) { return false; } return true; } /* }}} */ function do_change_record() /* {{{ */ { // Preparing queries $query_real = ''; $query_oldrec = ''; $newvals = array(); $oldvals = array(); $changed = array(); // Prepare query to retrieve oldvals for ($k = 0; $k < $this->num_fds; $k++) { if ($this->processed($k) && !$this->readonly($k)) { $fd = $this->fds[$k]; $fn = $this->get_data_cgi_var($fd); $newvals[$this->fds[$k]] = is_array($fn) ? join(',',$fn) : $fn; if ($query_oldrec == '') { $query_oldrec = 'SELECT '.$this->sd.$fd.$this->ed; } else { $query_oldrec .= ','.$this->sd.$fd.$this->ed; } } } $where_part = " WHERE (".$this->sd.$this->key.$this->ed.'='.$this->key_delim.$this->rec.$this->key_delim.')'; $query_newrec = $query_oldrec.' FROM ' . $this->tb; $query_oldrec .= ' FROM ' . $this->sd.$this->tb.$this->ed . $where_part; // Additional query (must go before real query) $res = $this->myquery($query_oldrec, __LINE__); $oldvals = $this->sql_fetch($res); $this->sql_free_result($res); // Creating array of changed keys ($changed) foreach ($newvals as $fd => $value) { if ($value != $oldvals[$fd]) $changed[] = $fd; } // Before trigger if ($this->exec_triggers('update', 'before', $oldvals, $changed, $newvals) == false) { return false; } // Build the real query respecting changes to the newvals array foreach ($newvals as $fd => $val) { if ($fd == '') continue; if ($this->col_has_sqlw($this->fdn[$fd])) { $val_as = addslashes($val); $val_qas = '"'.addslashes($val).'"'; $value = $this->substituteVars( $this->fdd[$this->fdn[$fd]]['sqlw'], array( 'val_qas' => $val_qas, 'val_as' => $val_as, 'val' => $val )); } else { $value = "'".addslashes($val)."'"; } if ($query_real == '') { $query_real = 'UPDATE '.$this->sd.$this->tb.$this->ed.' SET '.$this->sd.$fd.$this->ed.'='.$value; } else { $query_real .= ','.$this->sd.$fd.$this->ed.'='.$value; } } $query_real .= $where_part; // Real query $res = $this->myquery($query_real, __LINE__); $this->message = $this->sql_affected_rows($this->dbh).' '.$this->labels['record changed']; if (! $res) { return false; } // Another additional query (must go after real query) if (in_array($this->key, $changed)) { $this->rec = $newvals[$this->key]; // key has changed } $query_newrec .= ' WHERE ('.$this->key.'='.$this->key_delim.$this->rec.$this->key_delim.')'; $res = $this->myquery($query_newrec, __LINE__); $newvals = $this->sql_fetch($res); $this->sql_free_result($res); // Creating array of changed keys ($changed) $changed = array(); foreach ($newvals as $fd => $value) { if ($value != $oldvals[$fd]) $changed[] = $fd; } // Notify list if (@$this->notify['update'] || @$this->notify['all']) { if (count($changed) > 0) { $this->email_notify($oldvals, $newvals); } } // Note change in log table if ($this->logtable) { foreach ($changed as $key) { $qry = sprintf('INSERT INTO %s' .' (updated, user, host, operation, tab, rowkey, col, oldval, newval)' .' VALUES (NOW(), "%s", "%s", "update", "%s", "%s", "%s", "%s", "%s")', $this->logtable, addslashes($this->get_server_var('REMOTE_USER')), addslashes($this->get_server_var('REMOTE_ADDR')), addslashes($this->tb), addslashes($this->rec), addslashes($key), addslashes($oldvals[$key]), addslashes($newvals[$key])); $this->myquery($qry, __LINE__); } } // After trigger if ($this->exec_triggers('update', 'after', $oldvals, $changed, $newvals) == false) { return false; } return true; } /* }}} */ function do_delete_record() /* {{{ */ { // Additional query $query = 'SELECT * FROM '.$this->sd.$this->tb.$this->ed.' WHERE ('.$this->sd.$this->key.$this->ed.' = ' .$this->key_delim.$this->rec.$this->key_delim.')'; // ) $res = $this->myquery($query, __LINE__); $oldvals = $this->sql_fetch($res); $this->sql_free_result($res); // Creating array of changed keys ($changed) $changed = is_array($oldvals) ? array_keys($oldvals) : array(); $newvals = array(); // Before trigger if ($this->exec_triggers('delete', 'before', $oldvals, $changed, $newvals) == false) { return false; } // Real query $query = 'DELETE FROM '.$this->tb.' WHERE ('.$this->key.' = ' .$this->key_delim.$this->rec.$this->key_delim.')'; // ) $res = $this->myquery($query, __LINE__); $this->message = $this->sql_affected_rows($this->dbh).' '.$this->labels['record deleted']; if (! $res) { return false; } // Notify list if (@$this->notify['delete'] || @$this->notify['all']) { $this->email_notify($oldvals, false); } // Note change in log table if ($this->logtable) { $query = sprintf('INSERT INTO %s' .' (updated, user, host, operation, tab, rowkey, col, oldval, newval)' .' VALUES (NOW(), "%s", "%s", "delete", "%s", "%s", "%s", "%s", "")', $this->logtable, addslashes($this->get_server_var('REMOTE_USER')), addslashes($this->get_server_var('REMOTE_ADDR')), addslashes($this->tb), addslashes($this->rec), addslashes($key), addslashes(serialize($oldvals))); $this->myquery($query, __LINE__); } // After trigger if ($this->exec_triggers('delete', 'after', $oldvals, $changed, $newvals) == false) { return false; } return true; } /* }}} */ function email_notify($old_vals, $new_vals) /* {{{ */ { if (! function_exists('mail')) { return false; } if ($old_vals != false && $new_vals != false) { $action = 'update'; $subject = 'Record updated in'; $body = 'An item with '.$this->fdd[$this->key]['name'].' = ' .$this->key_delim.$this->rec.$this->key_delim .' was updated in'; $vals = $new_vals; } elseif ($new_vals != false) { $action = 'insert'; $subject = 'Record added to'; $body = 'A new item was added into'; $vals = $new_vals; } elseif ($old_vals != false) { $action = 'delete'; $subject = 'Record deleted from'; $body = 'An item was deleted from'; $vals = $old_vals; } else { return false; } $addr = $this->get_server_var('REMOTE_ADDR'); $user = $this->get_server_var('REMOTE_USER'); $body = 'This notification e-mail was automatically generated by phpMyEdit.'."\n\n".$body; $body .= ' table '.$this->tb.' in SQL database '.$this->db.' on '.$this->page_name; $body .= ' by '.($user == '' ? 'unknown user' : "user $user").' from '.$addr; $body .= ' at '.date('d/M/Y H:i').' with the following fields:'."\n\n"; $i = 1; foreach ($vals as $k => $text) { $name = isset($this->fdd[$k]['name~']) ? $this->fdd[$k]['name~'] : $this->fdd[$k]['name']; if ($action == 'update') { if ($old_vals[$k] == $new_vals[$k]) { continue; } $body .= sprintf("[%02s] %s (%s)\n WAS: %s\n IS: %s\n", $i, $name, $k, $old_vals[$k], $new_vals[$k]); } else { $body .= sprintf('[%02s] %s (%s): %s'."\n", $i, $name, $k, $text); } $i++; } $body .= "\n--\r\n"; // \r is needed for signature separating $body .= "phpMyEdit\ninstant SQL table editor and code generator\n"; $body .= "http://platon.sk/projects/phpMyEdit/\n\n"; $subject = @$this->notify['prefix'].$subject.' '.$this->dbp.$this->tb; $subject = trim($subject); // just for sure $wrap_w = intval(@$this->notify['wrap']); $wrap_w > 0 || $wrap_w = 72; $from = (string) @$this->notify['from']; $from != '' || $from = 'webmaster@'.strtolower($this->get_server_var('SERVER_NAME')); $headers = 'From: '.$from."\n".'X-Mailer: PHP/'.phpversion().' (phpMyEdit)'; $body = wordwrap($body, $wrap_w, "\n", 1); $emails = (array) $this->notify[$action] + (array) $this->notify['all']; foreach ($emails as $email) { if (! empty($email)) { mail(trim($email), $subject, $body, $headers); } } return true; } /* }}} */ /* * Apply triggers function * Run a (set of) trigger(s). $trigger can be an Array or a filename * Break and return false as soon as a trigger return false * we need a reference on $newvals to be able to change value before insert/update */ function exec_triggers($op, $step, $oldvals, &$changed, &$newvals) /* {{{ */ { if (! isset($this->triggers[$op][$step])) { return true; } $ret = true; $trig = $this->triggers[$op][$step]; if (is_array($trig)) { ksort($trig); for ($t = reset($trig); $t !== false && $ret != false; $t = next($trig)) { $ret = include($t); } } else { $ret = include($trig); } return $ret; } /* }}} */ function exec_triggers_simple($op, $step) /* {{{ */ { $oldvals = $newvals = $changed = array(); return $this->exec_triggers($op, $step, $oldvals, $changed, $newvals); } /* }}} */ /* * Recreate functions */ function recreate_fdd($default_page_type = 'L') /* {{{ */ { // TODO: one level deeper browsing $this->page_type = $default_page_type; $this->filter_operation() && $this->page_type = 'F'; $this->view_operation() && $this->page_type = 'V'; if ($this->add_operation() || $this->saveadd == $this->labels['Save'] || $this->moreadd == $this->labels['More']) { $this->page_type = 'A'; } if ($this->change_operation() || $this->savechange == $this->labels['Save'] || $this->morechange == $this->labels['Apply']) { $this->page_type = 'C'; } if ($this->copy_operation() || $this->savecopy == $this->labels['Save']) { $this->page_type = 'P'; } if ($this->delete_operation() || $this->savedelete == $this->labels['Delete']) { $this->page_type = 'D'; } // Restore backups (if exists) foreach (array_keys($this->fdd) as $column) { foreach (array_keys($this->fdd[$column]) as $col_option) { if ($col_option[strlen($col_option) - 1] != '~') continue; $this->fdd[$column][substr($col_option, 0, strlen($col_option) - 1)] = $this->fdd[$column][$col_option]; unset($this->fdd[$column][$col_option]); } } foreach (array_keys($this->fdd) as $column) { foreach (array_keys($this->fdd[$column]) as $col_option) { if (! strchr($col_option, '|')) { continue; } $col_ar = explode('|', $col_option, 2); if (! stristr($col_ar[1], $this->page_type)) { continue; } // Make field backups $this->fdd[$column][$col_ar[0] .'~'] = $this->fdd[$column][$col_ar[0]]; $this->fdd[$column][$col_option.'~'] = $this->fdd[$column][$col_option]; // Set particular field $this->fdd[$column][$col_ar[0]] = $this->fdd[$column][$col_option]; unset($this->fdd[$column][$col_option]); } } } /* }}} */ function recreate_displayed() /* {{{ */ { $field_num = 0; $num_fields_displayed = 0; $this->fds = array(); $this->fdn = array(); $this->displayed = array(); $this->guidance = false; foreach (array_keys($this->fdd) as $key) { if (preg_match('/^\d+$/', $key)) { // skipping numeric keys continue; } $this->fds[$field_num] = $key; $this->fdn[$key] = $field_num; /* We must use here displayed() function, because displayed[] array is not created yet. We will simultaneously create that array as well. */ if ($this->displayed[$field_num] = $this->displayed($field_num)) { $num_fields_displayed++; } if (is_array(@$this->fdd[$key]['values']) && ! isset($this->fdd[$key]['values']['table'])) { foreach ($this->fdd[$key]['values'] as $val) { $this->fdd[$key]['values2'][$val] = $val; } unset($this->fdd[$key]['values']); } isset($this->fdd[$key]['help']) && $this->guidance = true; $this->fdd[$field_num] = $this->fdd[$key]; $field_num++; } $this->num_fds = $field_num; $this->num_fields_displayed = $num_fields_displayed; $this->key_num = array_search($this->key, $this->fds); /* Adds first displayed column into sorting fields by replacing last array entry. Also remove duplicite values and change column names to their particular field numbers. Note that entries like [0]=>'9' [1]=>'-9' are correct and they will have desirable sorting behaviour. So there is no need to remove them. */ $this->sfn = array_unique($this->sfn); $check_ar = array(); foreach ($this->sfn as $key => $val) { if (preg_match('/^[-]?\d+$/', $val)) { // skipping numeric keys $val = abs($val); if (in_array($val, $check_ar) || $this->password($val)) { unset($this->sfn[$key]); } else { $check_ar[] = $val; } continue; } if ($val[0] == '-') { $val = substr($val, 1); $minus = '-'; } else { $minus = ''; } if (($val = array_search($val, $this->fds)) === false || $this->password($val)) { unset($this->sfn[$key]); } else { $val = intval($val); if (in_array($val, $check_ar)) { unset($this->sfn[$key]); } else { $this->sfn[$key] = $minus.$val; $check_ar[] = $val; } } } $this->sfn = array_unique($this->sfn); return true; } /* }}} */ function backward_compatibility() /* {{{ */ { foreach (array_keys($this->fdd) as $column) { // move ['required'] to ['js']['required'] if (! isset($this->fdd[$column]['js']['required']) && isset($this->fdd[$column]['required'])) { $this->fdd[$column]['js']['required'] = $this->fdd[$column]['required']; } // move 'HWR' flags from ['options'] into ['input'] if (isset($this->fdd[$column]['options'])) { stristr($this->fdd[$column]['options'], 'H') && $this->fdd[$column]['input'] .= 'H'; stristr($this->fdd[$column]['options'], 'W') && $this->fdd[$column]['input'] .= 'W'; stristr($this->fdd[$column]['options'], 'R') && $this->fdd[$column]['input'] .= 'R'; } } } /* }}} */ /* * Error handling function */ function error($message, $additional_info = '') /* {{{ */ { echo '

phpMyEdit error: ',htmlspecialchars($message),'

',"\n"; if ($additional_info != '') { echo '
',htmlspecialchars($additional_info); } return false; } /* }}} */ /* * Database connection function */ function connect() /* {{{ */ { if (isset($this->dbh)) { return true; } if (!isset($this->db)) { $this->error('no database defined'); return false; } if (!isset ($this->tb)) { $this->error('no table defined'); return false; } $this->sql_connect(); if (!$this->dbh) { $this->error('could not connect to SQL'); return false; } return true; } /* }}} */ /* * The workhorse */ function execute() /* {{{ */ { // DEBUG - uncomment to enable /* //phpinfo(); $this->print_get_vars(); $this->print_post_vars(); $this->print_vars(); echo "
query opts:\n";
		echo print_r($this->query_opts);
		echo "
\n"; echo "
get vars:\n";
		echo print_r($this->get_opts);
		echo "
\n"; */ // Let's do explicit quoting - it's safer set_magic_quotes_runtime(0); // Checking if language file inclusion was successful if (! is_array($this->labels)) { $this->error('could not locate language files', 'searched path: '.$this->dir['lang']); return false; } // Database connection if ($this->connect() == false) { return false; } /* * ====================================================================== * Pass 3: process any updates generated if the user has selected * a save or cancel button during Pass 2 * ====================================================================== */ // Cancel button - Cancel Triggers if ($this->add_canceled() || $this->copy_canceled()) { $this->exec_triggers_simple('insert', 'cancel'); } if ($this->view_canceled()) { $this->exec_triggers_simple('select', 'cancel'); } if ($this->change_canceled()) { $this->exec_triggers_simple('update', 'cancel'); } if ($this->delete_canceled()) { $this->exec_triggers_simple('delete', 'cancel'); } // Save/More Button - database operations if ($this->saveadd == $this->labels['Save'] || $this->savecopy == $this->labels['Save']) { $this->add_enabled() && $this->do_add_record(); unset($this->saveadd); unset($this->savecopy); $this->recreate_fdd(); } elseif ($this->moreadd == $this->labels['More']) { $this->add_enabled() && $this->do_add_record(); $this->operation = $this->labels['Add']; // to force add operation $this->recreate_fdd(); $this->recreate_displayed(); $this->backward_compatibility(); } elseif ($this->savechange == $this->labels['Save']) { $this->change_enabled() && $this->do_change_record(); unset($this->savechange); $this->recreate_fdd(); } elseif ($this->morechange == $this->labels['Apply']) { $this->change_enabled() && $this->do_change_record(); $this->operation = $this->labels['Change']; // to force change operation $this->recreate_fdd(); $this->recreate_displayed(); $this->backward_compatibility(); } elseif ($this->savedelete == $this->labels['Delete']) { $this->delete_enabled() && $this->do_delete_record(); unset($this->savedelete); $this->recreate_fdd(); } /* * ====================================================================== * Pass 2: display an input/edit/confirmation screen if the user has * selected an editing button on Pass 1 through this page * ====================================================================== */ if ($this->add_operation() || $this->change_operation() || $this->delete_operation() || $this->view_operation() || $this->copy_operation()) { $this->display_record(); } /* * ====================================================================== * Pass 1 and Pass 3: display the SQL table in a scrolling window on * the screen (skip this step in 'Add More' mode) * ====================================================================== */ else { $this->list_table(); } $this->sql_disconnect(); if ($this->display['time'] && $this->timer != null) { echo $this->timer->end(),' miliseconds'; } } /* }}} */ /* * Class constructor */ function phpMyEdit($opts) /* {{{ */ { // Set desirable error reporting level $error_reporting = error_reporting(E_ALL & ~E_NOTICE); // Database handle variables $this->sql_delimiter(); if (isset($opts['dbh'])) { $this->close_dbh = false; $this->dbh = $opts['dbh']; $this->dbp = ''; } else { $this->close_dbh = true; $this->dbh = null; $this->dbp = $this->sd.$opts['db'].$this->ed.'.'; $this->hn = $opts['hn']; $this->un = $opts['un']; $this->pw = $opts['pw']; $this->db = $opts['db']; } $this->tb = $opts['tb']; // Other variables $this->key = $opts['key']; $this->key_type = $opts['key_type']; $this->inc = $opts['inc']; $this->options = $opts['options']; $this->fdd = $opts['fdd']; $this->multiple = intval($opts['multiple']); $this->multiple <= 0 && $this->multiple = 2; $this->filters = is_array(@$opts['filters']) ? join(' AND ', $opts['filters']) : @$opts['filters']; $this->triggers = @$opts['triggers']; $this->notify = @$opts['notify']; $this->logtable = @$opts['logtable']; $this->page_name = @$opts['page_name']; if (! isset($this->page_name)) { $this->page_name = basename($this->get_server_var('PHP_SELF')); isset($this->page_name) || $this->page_name = $this->tb; } $this->display['query'] = @$opts['display']['query']; $this->display['sort'] = @$opts['display']['sort']; $this->display['time'] = @$opts['display']['time']; if ($this->display['time']) { $this->timer = new phpMyEdit_timer(); } $this->display['tabs'] = isset($opts['display']['tabs']) ? $opts['display']['tabs'] : true; $this->display['form'] = isset($opts['display']['form']) ? $opts['display']['form'] : true; $this->display['num_records'] = isset($opts['display']['num_records']) ? $opts['display']['num_records'] : true; $this->display['num_pages'] = isset($opts['display']['num_pages']) ? $opts['display']['num_pages'] : true; // Creating directory variables $this->dir['root'] = dirname(realpath(__FILE__)) . (strlen(dirname(realpath(__FILE__))) > 0 ? '/' : ''); $this->dir['lang'] = $this->dir['root'].'lang/'; // Creating URL variables $this->url['images'] = 'images/'; isset($opts['url']['images']) && $this->url['images'] = $opts['url']['images']; // CSS classes policy $this->css = @$opts['css']; !isset($this->css['separator']) && $this->css['separator'] = '-'; !isset($this->css['prefix']) && $this->css['prefix'] = 'pme'; !isset($this->css['page_type']) && $this->css['page_type'] = false; !isset($this->css['position']) && $this->css['position'] = false; !isset($this->css['divider']) && $this->css['divider'] = 2; $this->css['divider'] = intval(@$this->css['divider']); // JS overall configuration $this->js = @$opts['js']; !isset($this->js['prefix']) && $this->js['prefix'] = 'PME_js_'; // DHTML overall configuration $this->dhtml = @$opts['dhtml']; !isset($this->dhtml['prefix']) && $this->dhtml['prefix'] = 'PME_dhtml_'; // Navigation $this->navigation = @$opts['navigation']; if (! $this->nav_buttons() && ! $this->nav_text_links() && ! $this->nav_graphic_links()) { $this->navigation .= 'B'; // buttons are default } if (! $this->nav_up() && ! $this->nav_down()) { $this->navigation .= 'D'; // down position is default } $this->buttons = $opts['buttons']; // Language labels (must go after navigation) $this->labels = $this->make_language_labels(isset($opts['language']) ? $opts['language'] : $this->get_server_var('HTTP_ACCEPT_LANGUAGE')); // CGI variables $this->cgi = @$opts['cgi']; $this->cgi['persist'] = ''; if (@is_array($opts['cgi']['persist'])) { foreach ($opts['cgi']['persist'] as $key => $val) { if (is_array($val)) { foreach($val as $key2 => $val2) { $this->cgi['persist'] .= '&'.rawurlencode($key) .'['.rawurlencode($key2).']='.rawurlencode($val2); } } else { $this->cgi['persist'] .= '&'.rawurlencode($key).'='.rawurlencode($val); } } } foreach (array('operation', 'sys', 'data') as $type) { if (! isset($this->cgi['prefix'][$type])) { $this->cgi['prefix'][$type] = $this->get_default_cgi_prefix($type); } } // Sorting variables $this->sfn = $this->get_sys_cgi_var('sfn'); isset($this->sfn) || $this->sfn = array(); is_array($this->sfn) || $this->sfn = array($this->sfn); isset($opts['sort_field']) || $opts['sort_field'] = array(); is_array($opts['sort_field']) || $opts['sort_field'] = array($opts['sort_field']); $this->sfn = array_merge($this->sfn, $opts['sort_field']); // Form variables all around $this->fl = intval($this->get_sys_cgi_var('fl')); $this->fm = intval($this->get_sys_cgi_var('fm')); // $old_page = ceil($this->fm / abs($this->inc)) + 1; $this->qfn = $this->get_sys_cgi_var('qfn'); $this->sw = $this->get_sys_cgi_var('sw'); $this->rec = $this->get_sys_cgi_var('rec', ''); $this->navop = $this->get_sys_cgi_var('navop'); $navfmup = $this->get_sys_cgi_var('navfmup'); $navfmdown = $this->get_sys_cgi_var('navfmdown'); $navpnup = $this->get_sys_cgi_var('navpnup'); $navpndown = $this->get_sys_cgi_var('navpndown'); if($navfmdown!=NULL && $navfmdown != $this->fm) $this->navfm = $navfmdown; elseif($navfmup!=NULL && $navfmup != $this->fm) $this->navfm = $navfmup; elseif($navpndown!=NULL && ($navpndown-1)*$this->inc != $this->fm) $this->navfm = ($navpndown-1)*$this->inc; elseif($navpnup!=NULL && ($navpnup-1)*$this->inc != $this->fm) $this->navfm = ($navpnup-1)*$this->inc; else $this->navfm = $this->fm; $this->operation = $this->get_sys_cgi_var('operation'); $oper_prefix_len = strlen($this->cgi['prefix']['operation']); if (! strncmp($this->cgi['prefix']['operation'], $this->operation, $oper_prefix_len)) { $this->operation = $this->labels[substr($this->operation, $oper_prefix_len)]; } $this->saveadd = $this->get_sys_cgi_var('saveadd'); $this->moreadd = $this->get_sys_cgi_var('moreadd'); $this->canceladd = $this->get_sys_cgi_var('canceladd'); $this->savechange = $this->get_sys_cgi_var('savechange'); $this->morechange = $this->get_sys_cgi_var('morechange'); $this->cancelchange = $this->get_sys_cgi_var('cancelchange'); $this->savecopy = $this->get_sys_cgi_var('savecopy'); $this->cancelcopy = $this->get_sys_cgi_var('cancelcopy'); $this->savedelete = $this->get_sys_cgi_var('savedelete'); $this->canceldelete = $this->get_sys_cgi_var('canceldelete'); $this->cancelview = $this->get_sys_cgi_var('cancelview'); // Filter setting if (isset($this->sw)) { $this->sw == $this->labels['Search'] && $this->fl = 1; $this->sw == $this->labels['Hide'] && $this->fl = 0; //$this->sw == $this->labels['Clear'] && $this->fl = 0; } // TAB names $this->tabs = array(); // Setting key_delim according to key_type if ($this->key_type == 'real') { /* If 'real' key_type does not work, try change MySQL datatype from float to double */ $this->rec = doubleval($this->rec); $this->key_delim = ''; } elseif ($this->key_type == 'int') { $this->rec = intval($this->rec); $this->key_delim = ''; } else { $this->key_delim = '"'; // $this->rec remains unmodified } // Specific $fdd modifications depending on performed action $this->recreate_fdd(); // Extract SQL Field Names and number of fields $this->recreate_displayed(); // Issue backward compatibility $this->backward_compatibility(); // Gathering query options $this->gather_query_opts(); // Call to action !isset($opts['execute']) && $opts['execute'] = 1; $opts['execute'] && $this->execute(); // Restore original error reporting level error_reporting($error_reporting); } /* }}} */ } /* Modeline for ViM {{{ * vim:set ts=4: * vim600:fdm=marker fdl=0 fdc=0: * }}} */ ?>