/** * Get the Text_Wiki renderer * * Singleton to get the Text_Wiki instance properly configured for the * TIP system. You can specify an array of rules to use in the $rules * array, or leave it undefined to use all the available rules. * * @param array|null $rules The array of rules to enable * @param string|null $toc_title TOC title or null to use a default value * @param string|null $wiki_base Base URI for wiki links * @return Text_Wiki The renderer */ public static function &getWiki($rules = null, $toc_title = null, $wiki_base = '') { static $renderer = null; static $all_rules = array('Prefilter', 'Delimiter', 'Code', 'Function', 'Html', 'Raw', 'Include', 'Embed', 'Anchor', 'Heading', 'Toc', 'Horiz', 'Break', 'Blockquote', 'List', 'Deflist', 'Table', 'Image', 'Phplookup', 'Center', 'Paragraph', 'Url', 'Freelink', 'Interwiki', 'Wikilink', 'Colortext', 'Strong', 'Bold', 'Emphasis', 'Italic', 'Underline', 'Tt', 'Superscript', 'Subscript', 'Revise', 'Tighten'); static $base_rules = array('Prefilter', 'Break', 'Paragraph', 'Tighten'); if (is_null($renderer)) { require_once 'Text/Wiki.php'; isset($toc_title) || ($toc_title = TIP::getLocale('index', 'wiki')); $renderer =& Text_Wiki::singleton('Default'); $renderer->disable = array(); $renderer->setFormatConf('Xhtml', 'charset', 'UTF-8'); /* According to the following comment: * http://php.net/manual/function.htmlentities.php#78509 * "There's no sane reason to use htmlentities() instead of htmlspecialchars()" */ $renderer->setFormatConf('Xhtml', 'translate', HTML_SPECIALCHARS); $renderer->setRenderConf('Xhtml', 'url', array('target' => '', 'regexes' => array('|http://picasaweb\\.google\\.com/.*/photo/.*|' => array('TIP_Renderer', 'picasa2PhotoCallback'), '|http://picasaweb\\.google\\.com/.*/albumid/.*|' => array('TIP_Renderer', 'picasa2AlbumCallback')))); $renderer->setRenderConf('Xhtml', 'code', array('css' => 'programlisting')); $renderer->setRenderConf('Xhtml', 'toc', array('title' => '<p><strong>' . $toc_title . '</strong></p>', 'div_id' => 'idToc', 'use_ul' => true, 'collapse' => false)); $renderer->setRenderConf('Xhtml', 'freelink', array('pages' => null, 'view_url' => $wiki_base, 'new_text_pos' => null)); } if (is_array($rules)) { // Capitalize the $rules values $rules = array_map('ucfirst', array_map('strtolower', $rules)); // Join the forced rules $rules = array_merge($rules, $base_rules); // Get the real rules to apply $rules = array_intersect($all_rules, $rules); } else { $rules = $base_rules; } $renderer->rules = $rules; return $renderer; }
/** * End a transaction * * End the current transaction. If there's no active transaction, * raise an error and return false. * * The transaction is really ended when the last started transaction * is closed. For instance, if you call startTransaction() twice and * endTransaction() once, the data will be never committed. * * The error flag indicates if the transaction must be rolled back * ($commit = true) of committed ($commit = false). * * @param bool $commit Commit (if true) or rollback (if false) * @return bool true on success or false on errors */ public function endTransaction($commit) { if ($this->_transaction_ref == 0) { TIP::error('ending a never started transaction'); return false; } --$this->_transaction_ref; if ($this->_transaction_ref > 0) { return true; } $action = $commit ? TIP_TRANSACTION_COMMIT : TIP_TRANSACTION_ROLLBACK; return $this->transaction($action); }
protected static function checkOptions(&$options) { if (@is_string($options['data'])) { $options['data'] = array('path' => $options['data']); } // The data path is a required option if (!@is_array($options['data']) || !isset($options['data']['path'])) { return false; } TIP::arrayDefault($options, 'id_type', 'string'); TIP::arrayDefault($options['data'], 'data_engine', array('id' => 'youtube2', 'type' => array('data_engine', 'xml'), 'fields_xpath' => array('id' => 'media:group/yt:videoid', 'title' => 'media:group/media:title[@type="plain"]', 'description' => 'media:group/media:description[@type="plain"]', 'swfurl' => 'media:group/media:content[@yt:format="5"]/@url', 'thumbnail120x90' => 'media:group/media:thumbnail[@width="120" and @height="90"]/@url', 'thumbnail480x360' => 'media:group/media:thumbnail[@width="480" and @height="360"]/@url', 'date' => 'media:group/yt:uploaded', 'uploader' => 'media:group/media:credit[@role="uploader"]', 'author' => 'author/name', 'duration' => 'media:group/yt:duration/@seconds', 'hits' => 'yt:statistics/@viewCount', 'favorites' => 'yt:statistics/@favoriteCount', 'rating' => 'gd:rating/@average', 'raters' => 'gd:rating/@numRaters'))); return parent::checkOptions($options); }
/** * Get the relative URI of the cached file, if it exists * @param TIP_Template &$template The template to check * @return string|null URI to the cache or null on errors */ public function getCacheUri(&$template) { $dirs = array_merge($this->cache_root, $template->getProperty('path')); if (!is_readable(implode(DIRECTORY_SEPARATOR, $dirs))) { return null; } return TIP::buildUri($dirs); }
protected static function checkOptions(&$options) { TIP::arrayDefault($options, 'extension', '.rcbt'); return parent::checkOptions($options); }
/** * Render a row to an array * * Renders $row as required by toArray(), that is append to the row * data some missing info (the {{id}}, {{title}} and {{tooltip}} fields). * * @param array &$row The subject row * @param mixed $id The id of the row * @internal */ private function _rowToArray(&$row, $id) { isset($row['id']) || ($row['id'] = $id); // Use the custom "title_field" or // leave the default $row['title'] untouched if (isset($this->title_field) && $this->title_field != 'title') { $row['title'] = TIP::pickElement($this->title_field, $row); } // Try to set the custom tooltip field if (isset($this->tooltip_field) && $this->tooltip_field != 'tooltip') { $row['tooltip'] = TIP::pickElement($this->tooltip_field, $row); } }
/** * Perform a view action * * Runs the file identified by the 'view_template' property for the * specified row. The rendered result is appended to the page. * * @param mixed $id The identifier of the row to view * @return bool true on success or false on errors */ protected function actionView($id) { // The query is not strictly necessary but it is still performed // to avoid read actions on arbitrary files if (is_null($row =& $this->fromRow($id, false)) || !$this->_onView($row)) { return false; } // Check for html file existence $file = TIP::buildDataPath($this->id, $id); if (!is_readable($file)) { $this->endView(); return false; } $content =& TIP_Application::getGlobal('content'); $this->keys['id'] = $id; $this->keys[$this->title_field] = str_replace('.html', '', $id); $this->keys['content'] = file_get_contents($file); $this->keys[$this->creation_field] = TIP::formatDate('datetime_sql', filectime($file)); $this->keys[$this->edited_field] = TIP::formatDate('datetime_sql', filemtime($file)); if (empty($this->view_template)) { // On empty template, output the whole html file content // and set a viable "title" metatag $content .= $this->keys['content']; $title =& TIP_Application::getGlobal('title'); $title = $this->keys[$this->title_field] . ' (' . $title . ')'; } else { // Use a custom template $content .= $this->tagRun($this->view_template); } // Discard the generated content to decrease memory consumption unset($this->keys); $this->endView(); return true; }
private function _updateCount($id, $offset) { if (empty($this->count_field)) { return true; } // Global query (probably cached) if (is_null($view =& $this->startDataView())) { TIP::notifyError('select'); return false; } $rows =& $view->getProperty('rows'); $this->endView(); if (!isset($rows[$id])) { TIP::warning("row not found ({$id})"); TIP::notifyError('notfound'); return false; } $old_row =& $rows[$id]; $row[$this->count_field] = $old_row[$this->count_field] + $offset; if (!$this->data->updateRow($row, $old_row)) { TIP::notifyError('update'); return false; } $old_row[$this->count_field] += $offset; return true; }
private function &_getRows(&$data, $fields) { $path = $data->getProperty('path'); if (!array_key_exists($path, $this->_rows)) { if (strncmp($path, 'http://', 7) == 0) { $uri = $path; if (function_exists('curl_init')) { // CURL extension available: this should be the // first attempt because the dumb 'open_basedir' // directive can f**k up file_get_contents() $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $uri); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); $xml_data = curl_exec($curl); curl_close($curl); } else { if (in_array('http', stream_get_wrappers())) { // http wrapper present $xml_data = file_get_contents($uri); } else { // No viable way to use the http protocol $xml_data = false; } } } else { $uri = TIP::buildDataPath($data->getProperty('path')); $xml_data = file_get_contents($uri); } $xml_tree = false; if (is_string($xml_data)) { // Work-around to let SimpleXML be happy with the f*****g // default namespace $xml_data = str_replace(' xmlns=', ' fakens=', $xml_data); $xml_tree = @simplexml_load_string($xml_data); } if ($xml_tree) { // Takes only the first element matching "base_xpath" $xml = reset($xml_tree->xpath($this->base_xpath)); $this->_data =& $data; if (empty($fields)) { $this->_fields = array_keys($this->fields_xpath); } else { $this->_fields = $fields; } $nodes = $xml->xpath($this->row_xpath); $rows = $this->_nodesToRows($nodes); unset($nodes, $this->_fields, $this->_data); } else { $rows = array(); TIP::error("failed to load XML file ({$uri})"); } $this->_rows[$path] = $rows; } return $this->_rows[$path]; }
/** * Refresh the current user * * Refreshes the user id cache of TIP::getUserId() and the privileges * of the yet loaded module. */ private function _refreshUser() { // Refresh the new user id cache TIP::getUserId(true); // Refresh the privileges of the yet loaded modules $this->_refreshModule(TIP_Type::singleton('module')); }
private function _validate(&$row) { $this->getFields(false); // Keep only the keys that are fields $row = array_intersect_key($row, $this->_fields); if (isset($this->fieldset)) { // Apply the fieldset filter $row = array_intersect_key($row, array_flip($this->fieldset)); } // Check for empty set if (empty($row)) { TIP::error('no valid field found'); return false; } // Cast the set to the proper type $this->_castRow($row); return true; }
/** * Get the privilege for the specified module * * Returns the privilege for a module and the specified user. If $user * is omitted, the current user id is used. Check TIP_Privilege to see how the * privileges are used. * * @param string $module The requesting module identifier * @param mixed $user A user id * @return TIP_PRIVILEGE... The requested privilege */ public static function getPrivilege($module, $user = null) { static $privilege = false; if ($privilege === false) { $privilege =& TIP_Application::getSharedModule('privilege'); } if ($privilege) { return $privilege->getPrivilege($module, $user); } return TIP::getDefaultPrivilege($module, $user); }
private function _render() { if (!empty($this->_tree)) { return true; } $filter = $this->master->getProperty('data')->order($this->date_field); if (is_null($view =& $this->master->startDataView($filter))) { return false; } $rows =& $view->getProperty('rows'); if (empty($rows)) { $this->_tree = array(); $this->master->endView(); return true; } $tree =& $this->_tree; foreach ($rows as $id => &$row) { $action = str_replace('-id-', $id, $this->action); $row['url'] = TIP::buildActionUriFromTag($action, (string) $this->master); $row['title'] = $this->_renderField($this->title_field, $row); // Suppose the date is in SQL format $date = $row[$this->date_field]; list($y, $m, $day) = sscanf($date, "%d-%d-%d"); // Compute the year $year = sprintf('%04d', $y); if (!array_key_exists($year, $tree)) { $tree[$year] = array('title' => $year, 'url' => TIP::modifyActionUri(null, null, null, array($this->id => $year)), 'sub' => array(), 'ITEMS' => 0); isset($this->count_field) && ($tree[$year]['COUNT'] = 0); } ++$tree[$year]['ITEMS']; isset($this->count_field) && ($tree[$year]['COUNT'] += $row[$this->count_field]); // Compute the month $months =& $tree[$year]['sub']; $month = strftime('%B', mktime(0, 0, 0, $m, $day, $year)); $month_id = $year . sprintf('%02d', $m); if (!array_key_exists($month_id, $months)) { $months[$month_id] = array('title' => $month, 'url' => TIP::modifyActionUri(null, null, null, array($this->id => $month_id)), 'sub' => array(), 'ITEMS' => 0); isset($this->count_field) && ($months[$month_id]['COUNT'] = 0); } ++$months[$month_id]['ITEMS']; isset($this->count_field) && ($months[$month_id]['COUNT'] += $row[$this->count_field]); $months[$month_id]['sub'][$id] =& $row; isset($this->count_field) && ($row['COUNT'] = $row[$this->count_field]); } return true; }
/** * Get a localized text * * Given an $id and a $prefix, retrieves the localized text (in the locale * specified by the 'locale' option of the main TIP_Application) binded to * "$prefix.$id". This means the data object of TIP_Locale must have a * series of rows with prefix.id values as the primary key. * * The choice of splitting the key in $prefix and $id allows to perform * a sort of cached read, that is, to avoid multiple queries, a single * request for a specified prefix gets all the id of this prefix. * If you are sure the other id are not used (such as for the TIP_Notify * module) you can disable the cache by passig false to $cached. * * The $context associative array contains a series of key=>value pairs * that can be substituted in the localized text. The get() method will * search in the localized text for any key enclosed by '|' and will put * the corresponding value. For instance, if there is a 'size'=>200 in * the $context array, the text 'Max allowed size is |size|...' will * expand to 'Max allowed size is 200...'. * * @param string $id The identifier * @param string $prefix The prefix * @param array $context A context associative array * @param bool $cached Whether to perform or not a cached read * @return string|null The localized text or null if not found */ public function get($id, $prefix, $context, $cached) { $row_id = $prefix . '.' . $id; if (array_key_exists($row_id, $this->_cache)) { // Localized text found in the TIP_Locale cache $row =& $this->_cache[$row_id]; } elseif ($cached) { $filter = $this->data->filter('id', $prefix . '.%', 'LIKE'); if (is_null($view =& $this->startDataView($filter))) { TIP::error("no way to get localized text ({$row_id})"); return null; } $this->_cache += $view->getProperty('rows'); $this->endView(); if (array_key_exists($row_id, $this->_cache)) { $row =& $this->_cache[$row_id]; } else { // $row_id not found $this->_cache[$row_id] = null; return null; } } else { $row =& $this->data->getRow($row_id); if (is_null($this->_cache[$row_id] = $row)) { // $row_id not found return null; } } $text = $row[$this->locale]; if (is_null($context) || strpos($text, '|') === false) { return $text; } // There are some embedded keys to expand ... $token = explode('|', $text); foreach ($token as $n => $value) { // Odd tokens are keys if ($n & 1) { $token[$n] = array_key_exists($value, $context) ? $context[$value] : ''; } } return implode($token); }
function renderEntry($node, $level, $type) { $this->_name_stack[$level] = $node['title']; $name = implode($this->_glue, $this->_name_stack); $is_container = array_key_exists('sub', $node); // Array rendering if ($is_container && $this->_array_mode & 1 || !$is_container && $this->_array_mode & 2) { $this->_rows[$node['id']] = $name; } // Check for maximum level $is_deep = isset($this->_levels) && $level >= $this->_levels; $is_active = $type != HTML_MENU_ENTRY_INACTIVE; if ($is_deep && $level > $this->_levels + 1 || $is_deep && $level > $this->_levels && !$is_active && !end($this->_html[$level - 1]['active'])) { return; } // Verify if the current/active row is a container if ($is_active) { $this->_is_current_container = $is_container; } // Generate the XHTML content $content = $node['title']; $indent = str_repeat(' ', $level); isset($node['ITEMS']) && ($content .= ' (' . $node['ITEMS'] . ')'); $content = htmlspecialchars($content, ENT_QUOTES, 'UTF-8'); isset($node['COUNT']) && ($content = ' <var>' . $node['COUNT'] . ' </var>' . $content); $is_active && ($content = '<strong>' . $content . '</strong>'); if ($is_container) { // <em> for containers $content = '<em>' . $content . '</em>'; $is_deep && !$is_active && ($content = '<a href="' . TIP::toHtml($node['url']) . '">' . $content . '</a>'); } else { // Compute the tooltip, if defined isset($node['ITEMS']) && ($content .= ' (' . $node['ITEMS'] . ')'); if (array_key_exists('tooltip', $node)) { $tooltip = '" title="' . htmlspecialchars($node['tooltip'], ENT_QUOTES, 'UTF-8'); } else { $tooltip = ''; } // Use <span> for normal entries $content = '<a href="' . TIP::toHtml($node['url']) . $tooltip . '"><span>' . $content . '</span></a>'; } $content = "\n{$indent} <li>{$content}"; // Close previous <li> for non-starting entries isset($this->_html[$level]) && ($content = '</li>' . $content); if (isset($this->_html[$level])) { $this->_html[$level]['active'][] = $is_active; $this->_html[$level]['content'] .= $content; } else { $this->_html[$level] = array('active' => array($is_active), 'content' => $content); } }
/** * Check if a module exists * * Expands to true if the module module exists or to false * otherwise. This tag only checks if the logic file for the $params * module exists, does not load the module itsself nor change * the default module. * * Useful to provide conditional links between different modules. */ protected function tagModuleExists($params) { $file = TIP::buildLogicPath('module', $params) . '.php'; return is_readable($file) ? 'true' : 'false'; }
/** * Type instantiation * * Gets the singleton of a configured object. $id could be any identifier * defined in $GLOBALS['cfg']. * * An internal register is mantained to avoid singleton() calls with the * same $id. * * @param mixed $id Instance identifier * @param bool $required true if errors must be fatals * @return TIP_Type The reference to the requested instance or * false on errors */ public static function &getInstance($id, $required = true) { static $register = array(); global $cfg; $id = strtolower($id); if (class_exists('TIP_Application')) { $namespace = TIP_Application::getGlobal('namespace'); if (!empty($namespace) && isset($cfg[$namespace . '_' . $id])) { $id = $namespace . '_' . $id; } } if (array_key_exists($id, $register)) { return $register[$id]; } if (isset($cfg[$id])) { $options = $cfg[$id]; isset($options['id']) || ($options['id'] = $id); $instance =& TIP_Type::singleton($options); } else { $instance = null; } if (is_null($instance) && $required) { TIP::fatal("unable to instantiate the requested object ({$id})"); exit; } $register[$id] =& $instance; return $instance; }
/** * Append a log * * Appends a log message to the data source of the logger object. * * @param string $severity The text of the log * @param string $message A custom message */ public function log($severity, $message) { static $running = false; // The running flag avoid recursive calls to log() if ($running) { return false; } else { $running = true; } // Generate the backtrace $bt = debug_backtrace(); // Carefully scans the backtrace to find useful informations // and store them in the $code array $code = array('origin' => '', 'tag' => '', 'action' => '', 'template' => '', 'data' => ''); foreach ($bt as $n => $trace) { $function = isset($trace['function']) ? strtolower($trace['function']) : ''; if (!isset($code['origin'])) { // Skip the log wrappers if ($function == 'log' || $function == 'warning' || $function == 'error' || $function == 'fatal') { continue; } $code['origin'] = "{$trace['file']} on line {$trace['line']}"; } if ($function == 'gettag') { if (!array_key_exists('tag', $code)) { $module = $trace['class']; $name = $trace['args'][0]; $params = $trace['args'][1]; if (strlen($params) > 80) { $params = substr($params, 0, 77) . '...'; } $code['tag'] = "{$module}::getTag({$name}, {$params})"; } continue; } elseif ($function == 'callaction') { if (!array_key_exists('action', $code)) { $module = $trace['class']; $action = $trace['args'][0]; $code['action'] = "{$module}::callAction({$action})"; } continue; } $class = isset($trace['class']) ? strtolower($trace['class']) : ''; if ($class == 'tip_template') { if (!array_key_exists('template', $code)) { $last =& $bt[$n - 1]; if (is_object($last['args'][0])) { $template =& $last['args'][0]; $method = $last['function']; $code['template'] = "{$template} on method {$method}"; } } continue; } elseif ($class == 'tip_data') { if (!array_key_exists('data', $code)) { $last =& $bt[$n - 1]; if (is_object($last['args'][0])) { $data =& $last['args'][0]; $method = $last['function']; $code['data'] = "{$data} on method {$method}"; } } continue; } } unset($bt); $context = array('user' => TIP::getUserId(), 'when' => TIP::formatDate('datetime_sql'), 'severity' => $severity, 'message' => $message); $this->_cache[] = array_merge($context, $code); $running = false; return true; }
private function _mapType(&$field, $type) { // Fallback values $field['type'] = 'string'; $field['widget'] = null; $field['length'] = 0; switch (strtoupper($type)) { case 'BOOL': case 'BOOLEAN': $field['type'] = 'bool'; $field['widget'] = 'set'; break; case 'BIT': case 'TINYINT': case 'SMALLINT': case 'MEDIUMINT': case 'INT': case 'INTEGER': case 'BIGINT': $field['type'] = 'int'; break; case 'FLOAT': case 'DOUBLE': case 'DOUBLE PRECISION': case 'REAL': case 'DECIMAL': case 'DEC': case 'NUMERIC': case 'FIXED': $field['type'] = 'float'; break; case 'STRING': case 'CHAR': case 'VARCHAR': case 'BINARY': case 'VARBINARY': $field['type'] = 'string'; break; case 'TINYBLOB': case 'TINYTEXT': $field['type'] = 'string'; $field['widget'] = 'textarea'; $field['length'] = 255; break; case 'BLOB': case 'TEXT': $field['type'] = 'string'; $field['widget'] = 'textarea'; $field['length'] = 65535; break; case 'MEDIUMBLOB': case 'MEDIUMTEXT': $field['type'] = 'string'; $field['widget'] = 'textarea'; $field['length'] = 16777215; break; case 'LONGBLOB': case 'LONGTEXT': $field['type'] = 'string'; $field['widget'] = 'textarea'; $field['length'] = 4294967295.0; break; case 'ENUM': $field['type'] = 'string'; $field['widget'] = 'enum'; break; case 'SET': $field['type'] = 'string'; $field['widget'] = 'set'; break; case 'DATE': $field['type'] = 'string'; $field['widget'] = 'date'; $field['length'] = 10; break; case 'TIME': $field['type'] = 'string'; $field['widget'] = 'time'; $field['length'] = 8; break; case 'DATETIME': $field['type'] = 'string'; $field['widget'] = 'datetime'; $field['length'] = 19; break; case 'TIMESTAMP': $field['type'] = 'int'; $field['widget'] = 'datetime'; break; case 'YEAR': $field['type'] = 'string'; $field['length'] = 4; break; default: $field['type'] = 'string'; TIP::warning("field type not supported ({$type})"); } }
/** * Get the child module * * Checks for the child module existence and caches the request. * If $class is not specified, no attempts are made to get the * child module: only the cache is returned or an error is raised. * * This method provides also a way to validate the data engine, * that **must** be shared between this module and the child one * to allow //transation protected// commits. * * @param string|null $class The class to use * @return TIP_Content|null|false The requested child module, * null if not needed or * false on errors * @internal */ private function &_getChildModule($class = null) { // The true value is used as "uncached" value static $child = true; // Check for cached result if ($child !== true) { return $child; } // Check for request without $class (no autodiscovering) if (is_null($class)) { TIP::error('No previous child request performed'); $error = false; return $error; } // Check if the child module is required $child = TIP_Type::getInstance($this->id . '-' . $class, false); if (is_null($child)) { // No child module needed return $child; } // Get and check the child module $child_data = $child->getProperty('data'); if (!$child_data instanceof TIP_Data) { TIP::error("the child module has no data (child = {$class})"); $child = false; } elseif ($child_data->getProperty('engine') != $this->data->getProperty('engine')) { TIP::error("master and child data must share the same data engine (child = {$class})"); $child = false; } return $child; }
private function &_widgetLookup(&$field, $args) { $id = $field['id']; $label = $this->getLocale('label.' . $id); $info = TIP::getLocale('comment.' . $id, $this->locale_prefix); if (empty($args)) { // Try to get the lookup module from the $cfg array global $cfg; foreach ($cfg as $module_id => &$module_options) { if (@$module_options['master'] == $this->id && end($module_options['type']) == 'hierarchy') { $lookup_id = $module_id; break; } } } else { // Explicitely defined in the widget args $lookup_id = $args; } // On lookup module not found, build a default one // by appending '_hierarchy' to this module id isset($lookup_id) || ($lookup_id = $this->id . '_hierarchy'); ++$this->_tabindex; $element =& $this->_addElement('text', $id, array('size' => 8, 'maxlength' => 8)); $element->setInfo($info); if ($this->json) { // Add JSON params, if needed $params = array('sWidget' => 'lookup', 'sUriView' => TIP::buildActionUri($lookup_id, 'view')); if (!is_null(TIP::getOption($lookup_id, 'search_field'))) { // Enable search URI $params['sUriSearch'] = TIP::buildActionUri($lookup_id, 'search'); } $element->setComment(json_encode($params)); // Enable AHAH interactivity $element->setAttribute('class', 'ahah'); } return $element; }
public function cancelTransaction() { TIP::warning('cancelTransaction()'); return true; }
/** * Perform a vote action * * Runs the 'vote_template' template to get a confirmation on the vote and * adds the vote if confirmed. * * @param int $id The poll id * @param int $answer The answer id * @return bool true on success or false on errors */ protected function actionVote($id, $answer) { $expiration = @HTTP_Session2::get($this->id . '.expiration'); $voting = @HTTP_Session2::get($this->id . '.voting'); if ($voting && time() < $expiration) { TIP::notifyError('double'); return false; } if (is_null($row =& $this->fromRow($id, false))) { return false; } if (is_null($answer_label = $this->getField('answer' . $answer))) { TIP::notifyError('wrongparams'); $this->endView(); return false; } if (@TIP::getGet('process', 'int') == 1) { if (!$voting) { TIP::notifyError('nocookies'); $this->endView(); return false; } $old_row = $row; ++$row['votes' . $answer]; $this->_onDataRow($row); $this->data->updateRow($row, $old_row); HTTP_Session2::set($this->id . '.voting', false); HTTP_Session2::set($this->id . '.expiration', strtotime($this->expiration)); $this->appendToPage($this->view_template); } else { HTTP_Session2::set($this->id . '.voting', true); $this->appendToPage($this->vote_template); } $this->endView(); return true; }
/** * Update the history on a master row deletion * * Updates the linked list by skipping the deleted history row * before deleting the row itsself. */ public function _onMasterDelete(&$row, $old_row) { $master_data =& $this->master->getProperty('data'); $id = $row[$master_data->getProperty('primary_key')]; $engine =& $this->data->getProperty('engine'); $query = $this->data->rowFilter($id); // Start the transaction here to avoid race conditions if (!$engine->startTransaction()) { // This error must be caught here to avoid the rollback return false; } // Get the current version row if (!($view =& $this->startDataView($query))) { $engine->endTransaction(false); return false; } $current_row = $view->current(); $this->endView(); if (empty($current_row)) { // No history found: return operation done (just in case...) return $engine->endTransaction(true); } // Get the previous version row $query = $this->data->filter($this->next_field, $id); if (!($view =& $this->startDataView($query))) { $engine->endTransaction(false); TIP::warning("no row to delete ({$id})"); TIP::notifyError('notfound'); return false; } $previous_row = $view->current(); $this->endView(); // Perform the operations $done = $this->data->deleteRow($id); if ($done && is_array($previous_row)) { // Update the next_field of previous_row $new_previous_row = $previous_row; $new_previous_row[$this->next_field] = $current_row[$this->next_field]; $done = $this->data->updateRow($new_previous_row, $previous_row); } // Close the transaction $done = $engine->endTransaction($done) && $done; return $done; }
private static function _renderRow($row, $options = null) { $id = TIP::toHtml($row['id']); $description = TIP::toHtml($row['description']); $src = TIP::toHtml($row['thumbnail']); $width = (int) $row['thumbnail_width']; $height = (int) $row['thumbnail_height']; $attrs = 'href="' . $id . '"'; empty($description) || ($attrs .= ' title="' . $description . '"'); isset($options['class']) && ($attrs .= ' class="' . $options['class'] . '"'); if (isset($options['max-width']) && $width > $options['max-width']) { $options['max-width'] = $width; } if (isset($options['max-height']) && $height > $options['max-height']) { $options['max-height'] = $height; } return "<a {$attrs}><img src=\"{$src}\" width=\"{$width}\" height=\"{$height}\" alt=\"{$description}\" /></a>\n"; }
/** * Perform an add action * * Overrides the default add action, assuring the 'browse_field' has a * valid value. * * @param mixed $id The identifier of the row to duplicate * @param array $options Options to pass to the form() call * @return bool true on success or false on errors */ protected function actionAdd($id, $options = array()) { // Merge the argument before the parent actionAdd(), so also // the defaults here defined can be overriden in configuration if (isset($this->form_options['add'])) { $options = array_merge($this->form_options['add'], $options); } // Check for the default value of 'browse_field' (the parent id) if (!isset($options['defaults'], $options['defaults'][$this->browse_field])) { // Try to get the parent id from GET or POST if (is_null($parent_id = $this->fromGetOrPost($this->browse_field))) { return false; } $options['defaults'][$this->browse_field] = $parent_id; } else { $parent_id = $options['defaults'][$this->browse_field]; } TIP::arrayDefault($options, 'follower', TIP::buildActionUri($this->master, 'view', $parent_id)); return parent::actionAdd($id, $options); }
/** * Process an add action * * Overrides the default callback providing email notification * when requested. * * @param array &$row The subject row * @param array|null $old_row The old row or null on no old row * @return bool true on success, false on errors */ public function _onAdd(&$row, $old_row) { if (!parent::_onAdd($row, $old_row)) { return false; } if (empty($this->notify_to)) { // No notification required return true; } $eol = "\r\n"; $env = 'TiP-' . TIP_VERSION_BRANCH; $sys = 'PHP-' . phpversion(); $headers = 'From: ' . $this->_getServerEmail() . $eol; $headers .= 'X-Mailer: TIP_Request module ' . "({$env}; {$sys})" . $eol; $headers .= 'MIME-Version: 1.0' . $eol; $headers .= 'Content-Type: text/plain; charset=ISO-8859-1'; // Assign current_row, so getField() checks for values in this row $this->_current_row =& $row; ob_start(); if ($this->tryRun($this->message_template)) { $message = ob_get_clean(); } elseif (array_key_exists($this->message_template, $row)) { ob_end_clean(); $message = $row[$this->message_template]; } else { ob_end_clean(); $message = 'Undefined message'; } $message = wordwrap(utf8_decode($message), 66); if (!mail($this->notify_to, $this->subject_text, $message, $headers)) { TIP::warning("Unable to send an email message to {$this->notify_to}"); return false; } return true; }
/** * Perform a browse action * * Overrides the "browse" action to substitute {terms} in the query URI. * * @param array &$conditions The browse conditions * @return bool true on success or false on errors */ protected function actionBrowse(&$conditions) { // Prepare the terms: append " site:thisdomain" to limit the query // to the current site $terms = TIP::getGetOrPost('terms', 'string'); $terms .= ' site:' . $_SERVER['SERVER_NAME']; $query =& $this->data->getProperty('path'); $query = str_replace('{terms}', urlencode($terms), $query); return parent::actionBrowse($conditions); }
private function _startSession() { // Start the session TIP::startSession(); $this->_session_started = true; // Set $_referer $request = HTTP_Session2::get('request'); $referer = HTTP_Session2::get('referer'); if (is_null($request)) { // Entry page or new session: the referer is the main page $this->_referer = null; } elseif ($this->_request['uri'] == $referer['uri']) { // Current URI equals to the old referer URI: probably a back action $this->_referer = null; } elseif ($this->_request['module'] != $request['module'] || $this->_request['action'] != $request['action']) { // New action: the referer is the previous request $this->_referer = $request; } else { // Same action: leave the old referer $this->_referer = $referer; } if (!is_array($this->_referer)) { $this->_referer = array('uri' => TIP::getHome(), 'module' => null, 'action' => null); $this->_referer['action'] = null; } $this->keys['REFERER'] = $this->_referer['uri']; // Store request and referer HTTP_Session2::set('referer', $this->_referer); HTTP_Session2::set('request', $this->_request); // Profiler initialization in "admin" mode if ($this->keys['IS_ADMIN']) { require_once 'Benchmark/Profiler.php'; $GLOBALS['_tip_profiler'] = new Benchmark_Profiler(); $GLOBALS['_tip_profiler']->start(); } }
private function _getUser() { if (!array_key_exists('UID', $this->keys)) { if (!is_null($user = $this->fromGet('id')) && $this->privilege < TIP_PRIVILEGE_MANAGER && $user == TIP::getUserId()) { TIP::notifyError('denied'); $user = null; } $this->keys['UID'] = $user; } return $this->keys['UID']; }