Esempio n. 1
0
 protected function runManagerAction($action)
 {
     switch ($action) {
         case 'phpinfo':
             ob_start();
             phpinfo();
             $this->content .= ob_get_clean();
             return true;
         case 'clear':
             if (is_null($dir = TIP::getGet('id', 'string'))) {
                 TIP::warning("GET not found ({$id})");
                 TIP::notifyError('noparams');
                 return false;
             }
             $dir = TIP::buildDataPath(urldecode($dir));
             TIP::removeDir($dir, false);
             TIP::notifyInfo('done');
             return true;
     }
     return null;
 }
Esempio n. 2
0
 /**
  * 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;
 }
Esempio n. 3
0
 /**
  * Execute a template file
  *
  * Parses and executes a template.
  *
  * @param  TIP_Template &$template The template to run
  * @param  TIP_Module   &$caller   The caller module
  * @return bool                    true on success or false on errors
  */
 public function run(&$template, &$caller)
 {
     $path =& $template->getProperty('path');
     // Check for cached result
     if ($this->caching) {
         $cache = implode(DIRECTORY_SEPARATOR, array_merge($this->cache_root, $path));
         if (is_readable($cache)) {
             return readfile($cache) !== false;
         }
     }
     // Check for compiled file
     if ($this->compiling) {
         $compiled = implode(DIRECTORY_SEPARATOR, array_merge(array('.'), $this->compiled_root, $path)) . '.php';
         if (is_readable($compiled)) {
             return (include $compiled) !== false;
         }
     }
     // No cache or compiled file found: parse and run this template
     $file = $template->__toString();
     isset($this->extension) && ($file .= $this->extension);
     isset($template->_buffer) || ($template->_buffer = file_get_contents($file));
     if ($template->_buffer === false) {
         TIP::error("unable to read file ({$file})");
         return false;
     }
     ob_start();
     $result = $this->runBuffer($template, $caller);
     if (is_string($result)) {
         ob_end_clean();
         TIP::error($result);
         return false;
     }
     if ($result == false && isset($cache)) {
         // Caching requested
         $dir = dirname($cache);
         if (is_dir($dir) || mkdir($dir, 0777, true)) {
             file_put_contents($cache, ob_get_contents(), LOCK_EX);
         } else {
             TIP::warning("Unable to create the cache path ({$dir})");
         }
     } elseif (isset($compiled)) {
         // Compiling requested
         $result = $this->compileBuffer($template);
         if (is_string($result)) {
             // Compilation successfull
             $dir = dirname($compiled);
             if (is_dir($dir) || mkdir($dir, 0777, true)) {
                 file_put_contents($compiled, $result, LOCK_EX);
             } else {
                 TIP::warning("Unable to create the compiled path ({$dir})");
             }
         }
     }
     ob_end_flush();
     return true;
 }
Esempio n. 4
0
 private function _addCustomRules($id)
 {
     $text = @$this->fields[$id]['rules'];
     if (empty($text)) {
         return;
     }
     $rules = explode(',', $text);
     foreach ($rules as $rule) {
         $open_brace = strpos($rule, '(');
         if ($open_brace === false) {
             $type = $rule;
             $format = '';
         } else {
             $close_brace = strrpos($rule, ')');
             if ($close_brace === false || $close_brace < $open_brace) {
                 TIP::warning("invalid custom rule for field {$id} ({$rule})");
                 continue;
             }
             $type = substr($rule, 0, $open_brace);
             $format = substr($rule, $open_brace + 1, $close_brace - $open_brace - 1);
             if (strpos($format, ' ')) {
                 $format = explode(' ', $format);
             }
         }
         $this->_addRule($id, $type, $format);
     }
 }
Esempio n. 5
0
 /**
  * Check if a row is not owned by the current user
  *
  * Similar to isOwner(), but works in the reverse way: check if the row
  * identified by $id is NOT owned by the current user.
  *
  * @param  mixed $id The row id
  * @return bool      true if not owned by the current user or false on errors
  */
 public function isNotOwner($id = null)
 {
     if (is_null($row =& $this->fromRow($id))) {
         return false;
     }
     if ($this->_isOwner($row) === true) {
         TIP::warning("owned row ({$id})");
         TIP::notifyError('denied');
         return false;
     }
     return true;
 }
Esempio n. 6
0
 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;
 }
Esempio n. 7
0
 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})");
     }
 }
Esempio n. 8
0
 /**
  * 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;
 }
Esempio n. 9
0
 /**
  * Get a localized text
  *
  * Gets the localized text for a specified module. $id is prefixed by the
  * 'locale_prefix' property.
  *
  * This method always returns a valid string: if the localized text
  * can't be retrieved, a string containing prefix.$id is returned and a
  * warning message is logged.
  *
  * See the TIP_Locale::get() method for technical details on how the text
  * is localized.
  *
  * @param  string $id      The identifier
  * @param  array  $context A context associative array
  * @param  bool   $cached  Whether to perform or not a cached read
  * @return string          The requested localized text
  */
 protected function getLocale($id, $context = null, $cached = true)
 {
     $text = TIP::getLocale($id, $this->locale_prefix, $context, $cached);
     if (empty($text)) {
         $text = $this->locale_prefix . '.' . $id;
         TIP::warning("localized text not found ({$text})");
     }
     return $text;
 }
Esempio n. 10
0
 /**
  * Process a delete action
  *
  * Overrides the default delete action erasing both master and child rows.
  */
 public function _onDelete(&$row, $old_row)
 {
     $child =& $this->_getChildModule();
     if (is_null($child)) {
         // No child module: chain-up the parent method
         return parent::_onDelete($row, $old_row);
     } elseif (!$child) {
         // An error occurred somewhere: do nothing
         return false;
     }
     $primary_key = $this->data->getProperty('primary_key');
     if (!array_key_exists($primary_key, $row) || is_null($id = $row[$primary_key])) {
         TIP::warning("no primary key defined (field {$primary_key})");
         return false;
     }
     $engine =& $this->data->getProperty('engine');
     if (!$engine->startTransaction()) {
         // This error must be caught here to avoid the rollback
         return false;
     }
     $done = parent::_onDelete($row, $old_row) && $child->getProperty('data')->deleteRow($id);
     $done = $engine->endTransaction($done) && $done;
     return $done;
 }
Esempio n. 11
0
 public function cancelTransaction()
 {
     TIP::warning('cancelTransaction()');
     return true;
 }
Esempio n. 12
0
 public function &select(&$data, $filter, $fields)
 {
     // Always work on a copy of the cached rows
     $rows = $this->_getRows($data, $fields);
     if (empty($rows)) {
         return $rows;
     }
     if (!empty($filter)) {
         // Provide basic SQL filtering
         if (!preg_match('"^\\s*(?:WHERE\\s+(\\S+?)\\s*(=|<>|>|<)\\s*(\\S+))?\\s*(?:LIMIT\\s*(\\d+)(?:\\s*,\\s*(\\d+))?)?\\s*$"i', $filter, $matches)) {
             // Unrecognized query: raise a warning and returns an empty set
             TIP::warning("query not recognized ({$filter})");
             $rows = array();
             return $rows;
         }
         $field = @$matches[1];
         $operator = @$matches[2];
         $value = @$matches[3];
         $length = @$matches[4];
         $offset = @$matches[5];
         // Apply the WHERE clause
         if (!empty($field)) {
             // Change the assignment to the (expected) comparison operator
             $operator == '=' && ($operator = '==');
             // Array filtering
             $callback = create_function('$row', "return \$row['{$field}']{$operator}'{$value}';");
             $rows = array_filter($rows, $callback);
         }
         // Apply the LIMIT clause
         if (!empty($length)) {
             // array reduction (the LIMIT clause)
             isset($offset) || ($offset = 0);
             $rows = array_slice($rows, $offset, $length);
         }
     }
     return $rows;
 }
Esempio n. 13
0
 private function _castField(&$value, $key)
 {
     if (array_key_exists($key, $this->_fields)) {
         $field =& $this->_fields[$key];
         if ((!is_null($value) || !@$field['can_be_null']) && !settype($value, $field['type'])) {
             TIP::warning("invalid type for field['{$key}'] => {$value} ({$field['type']})");
         }
     }
 }
Esempio n. 14
0
 /**
  * Get the timestamp from a special date
  *
  * Parses $date, specified in $format format, and return the timestamp.
  * The currently supported formats are:
  * - 'sql' for SQL date or datetime (YYYY-MM-DD hh:mm:ss)
  *
  * @param  mixed    $date   The input date
  * @param  string   $format A supported date format
  * @return int|null         $date converted in timestamp or null on errors
  */
 public static function getTimestamp($date, $format)
 {
     switch ($format) {
         case 'sql':
             @(list($year, $month, $day, $hour, $min, $sec) = sscanf($date, '%d-%d-%d %d:%d:%d'));
             return mktime($hour, $min, $sec, $month, $day, $year);
     }
     TIP::warning("Input time format not recognized ({$format})");
     return null;
 }
Esempio n. 15
0
 private function _renderField($field, &$row)
 {
     if (is_string($field)) {
         return $row[$field];
     } elseif (is_array($field)) {
         return implode(', ', array_intersect_key($row, array_flip($field)));
     }
     // No way to render this field
     $field_type = gettype($field);
     TIP::warning("not a valid field type ({$field_type})");
     return '';
 }
Esempio n. 16
0
 /**
  * Get the privilege level from a privilege id
  *
  * The reverse operation of tagPrivilegeId().
  */
 protected function tagPrivilegeLevel($params)
 {
     $level = array_search($params, $this->_privileges);
     if ($level === false) {
         TIP::warning("undefined privilege id ({$params})");
         return null;
     }
     return $level;
 }