/** * General constructor for searches. * * @param string $event The admin-side event to which this search relates * @param string $methods Available search methods * @param string $crit Criteria to be used in filter. If omitted, uses GET/POST value * @param string $method Search method(s) to filter by. If omitted, uses GET/POST value or last-used method */ public function __construct($event, $methods, $crit = null, $method = null) { $this->event = $event; callback_event_ref('search_criteria', $event, 0, $methods); $this->setMethods($methods); if ($crit === null) { $this->crit = gps('crit'); } if ($method === null) { $this->search_method = gps('search_method'); if ($this->search_method === '') { $this->search_method = unserialize(get_pref('search_options_' . $event)); } } $this->verbatim = (bool) preg_match('/^"(.*)"$/', $this->crit, $m); $this->crit_escaped = $this->verbatim ? doSlash($m[1]) : doLike($this->crit); }
function discuss_save() { $varray = array_map('assert_string', gpsa(array('email', 'name', 'web', 'message', 'ip'))); $varray = $varray + array_map('assert_int', gpsa(array('discussid', 'visible', 'parentid'))); extract(doSlash($varray)); $message = $varray['message'] = preg_replace('#<(/?txp:.+?)>#', '<$1>', $message); $constraints = array('status' => new ChoiceConstraint($visible, array('choices' => array(SPAM, MODERATE, VISIBLE), 'message' => 'invalid_status'))); callback_event_ref('discuss_ui', 'validate_save', 0, $varray, $constraints); $validator = new Validator($constraints); if ($validator->validate() && safe_update("txp_discuss", "email = '{$email}',\n\t\t\t name = '{$name}',\n\t\t\t web = '{$web}',\n\t\t\t message = '{$message}',\n\t\t\t visible = {$visible}", "discussid = {$discussid}")) { update_comments_count($parentid); update_lastmod(); $message = gTxt('comment_updated', array('{id}' => $discussid)); } else { $message = array(gTxt('comment_save_failed'), E_ERROR); } discuss_list($message); }
/** * Filter raw input text by calling one of our known Textfilters by its key. * * Invokes the 'textfilter.filter' pre- and post-callbacks. * * @param string $key The Textfilter's key * @param string $thing Raw input text * @param array $context Filter context ('options' => array, 'field' => string, 'data' => mixed) * @return string Filtered output text * @throws Exception */ public function filter($key, $thing, $context) { // Preprocessing, anyone? callback_event_ref('textfilter', 'filter', 0, $thing, $context); if (isset($this[$key])) { $thing = $this[$key]->filter($thing, $context['options']); } else { throw new Exception(gTxt('invalid_argument', array('{name}' => 'key'))); } // Postprocessing, anyone? callback_event_ref('textfilter', 'filter', 1, $thing, $context); return $thing; }
function link_save() { global $vars, $txp_user; $varray = array_map('assert_string', gpsa($vars)); extract(doSlash($varray)); if ($id) { $id = $varray['id'] = assert_int($id); } if ($linkname === '' && $url === '' && $description === '') { link_list(array(gTxt('link_empty'), E_ERROR)); return; } $author = fetch('author', 'txp_link', 'id', $id); if (!has_privs('link.edit') && !($author == $txp_user && has_privs('link.edit.own'))) { link_list(gTxt('restricted_area')); return; } if (!$linksort) { $linksort = $linkname; } $constraints = array('category' => new CategoryConstraint($varray['category'], array('type' => 'link'))); callback_event_ref('link_ui', 'validate_save', 0, $varray, $constraints); $validator = new Validator($constraints); if ($validator->validate()) { if ($id) { $ok = safe_update('txp_link', "category = '{$category}',\n\t\t\t\t\turl = '" . trim($url) . "',\n\t\t\t\t\tlinkname = '{$linkname}',\n\t\t\t\t\tlinksort = '{$linksort}',\n\t\t\t\t\tdescription = '{$description}',\n\t\t\t\t\tauthor = '" . doSlash($txp_user) . "'", "id = {$id}"); } else { $ok = safe_insert('txp_link', "category = '{$category}',\n\t\t\t\t\tdate = now(),\n\t\t\t\t\turl = '" . trim($url) . "',\n\t\t\t\t\tlinkname = '{$linkname}',\n\t\t\t\t\tlinksort = '{$linksort}',\n\t\t\t\t\tdescription = '{$description}',\n\t\t\t\t\tauthor = '" . doSlash($txp_user) . "'"); if ($ok) { $GLOBALS['ID'] = $_POST['id'] = $ok; } } if ($ok) { // update lastmod due to link feeds update_lastmod(); $message = gTxt($id ? 'link_updated' : 'link_created', array('{name}' => doStrip($linkname))); } else { $message = array(gTxt('link_save_failed'), E_ERROR); } } else { $message = array(gTxt('link_save_failed'), E_ERROR); } link_list($message); }
/** * Render a multi-edit form listing editing methods * * @param array $options array('value' => array( 'label' => '', 'html' => '' ),...) * @param string $event Event * @param string $step Step * @param integer $page Page number * @param string $sort Column sorted by * @param string $dir Sorting direction * @param string $crit Search criterion * @param string $search_method Search method * @return string HTML */ function multi_edit($options, $event = null, $step = null, $page = '', $sort = '', $dir = '', $crit = '', $search_method = '') { $html = $methods = array(); $methods[''] = gTxt('with_selected_option'); if ($event === null) { global $event; } if ($step === null) { $step = $event . '_multi_edit'; } callback_event_ref($event . '_ui', 'multi_edit_options', 0, $options); foreach ($options as $value => $option) { if (is_array($option)) { $methods[$value] = $option['label']; if (isset($option['html'])) { $html[$value] = '<div class="multi-option multi-option-' . txpspecialchars($value) . '">' . $option['html'] . '</div>'; } } else { $methods[$value] = $option; } } return '<div class="multi-edit">' . n . selectInput('edit_method', $methods, '') . n . eInput($event) . n . sInput($step) . n . hInput('page', $page) . ($sort ? n . hInput('sort', $sort) . n . hInput('dir', $dir) : '') . ($crit !== '' ? n . hInput('crit', $crit) . n . hInput('search_method', $search_method) : '') . n . implode('', $html) . n . fInput('submit', '', gTxt('go')) . n . '</div>'; }
/** * Validates article data. * * @param array $rs Article data * @param string|array $msg Initial message * @return string HTML */ function article_validate($rs, &$msg) { global $prefs, $step, $statuses; if (!empty($msg)) { return false; } $constraints = array('Status' => new ChoiceConstraint($rs['Status'], array('choices' => array_keys($statuses), 'message' => 'invalid_status')), 'Section' => new SectionConstraint($rs['Section']), 'Category1' => new CategoryConstraint($rs['Category1'], array('type' => 'article')), 'Category2' => new CategoryConstraint($rs['Category2'], array('type' => 'article')), 'textile_body' => new \Textpattern\Textfilter\Constraint($rs['textile_body'], array('message' => 'invalid_textfilter_body')), 'textile_excerpt' => new \Textpattern\Textfilter\Constraint($rs['textile_excerpt'], array('message' => 'invalid_textfilter_excerpt'))); if (!$prefs['articles_use_excerpts']) { $constraints['excerpt_blank'] = new BlankConstraint($rs['Excerpt'], array('message' => 'excerpt_not_blank')); } if (!$prefs['use_comments']) { $constraints['annotate_invite_blank'] = new BlankConstraint($rs['AnnotateInvite'], array('message' => 'invite_not_blank')); $constraints['annotate_false'] = new FalseConstraint($rs['Annotate'], array('message' => 'comments_are_on')); } if ($prefs['allow_form_override']) { $constraints['override_form'] = new FormConstraint($rs['override_form'], array('type' => 'article')); } else { $constraints['override_form'] = new BlankConstraint($rs['override_form'], array('message' => 'override_form_not_blank')); } callback_event_ref('article_ui', "validate_{$step}", 0, $rs, $constraints); $validator = new Validator($constraints); if ($validator->validate()) { $msg = ''; return true; } else { $msg = doArray($validator->getMessages(), 'gTxt'); $msg = array(join(', ', $msg), E_ERROR); return false; } }
function file_save() { global $file_base_path, $file_statuses, $txp_user; $varray = array_map('assert_string', gpsa(array('id', 'category', 'title', 'description', 'status', 'publish_now', 'year', 'month', 'day', 'hour', 'minute', 'second'))); extract(doSlash($varray)); $filename = $varray['filename'] = sanitizeForFile(gps('filename')); if ($filename == '') { file_list(array(gTxt('file_not_updated', array('{name}' => $filename)), E_ERROR)); return; } $id = $varray['id'] = assert_int($id); $permissions = gps('perms'); if (is_array($permissions)) { asort($permissions); $permissions = implode(",", $permissions); } $varray['permissions'] = $permissions; $perms = doSlash($permissions); $rs = safe_row('filename, author', 'txp_file', "id={$id}"); if (!has_privs('file.edit') && !($rs['author'] === $txp_user && has_privs('file.edit.own'))) { require_privs(); } $old_filename = $varray['old_filename'] = sanitizeForFile($rs['filename']); if ($old_filename != false && strcmp($old_filename, $filename) != 0) { $old_path = build_file_path($file_base_path, $old_filename); $new_path = build_file_path($file_base_path, $filename); if (file_exists($old_path) && shift_uploaded_file($old_path, $new_path) === false) { file_list(array(gTxt('file_cannot_rename', array('{name}' => $filename)), E_ERROR)); return; } else { file_set_perm($new_path); } } $created_ts = @safe_strtotime($year . '-' . $month . '-' . $day . ' ' . $hour . ':' . $minute . ':' . $second); if ($publish_now) { $created = 'now()'; } elseif ($created_ts > 0) { $created = "from_unixtime('" . $created_ts . "')"; } else { $created = ''; } $size = filesize(build_file_path($file_base_path, $filename)); $constraints = array('category' => new CategoryConstraint(gps('category'), array('type' => 'file')), 'status' => new ChoiceConstraint(gps('status'), array('choices' => array_keys($file_statuses), 'message' => 'invalid_status'))); callback_event_ref('file_ui', 'validate_save', 0, $varray, $constraints); $validator = new Validator($constraints); $rs = $validator->validate() && safe_update('txp_file', "\n filename = '" . doSlash($filename) . "',\n title = '{$title}',\n category = '{$category}',\n permissions = '{$perms}',\n description = '{$description}',\n status = '{$status}',\n size = '{$size}',\n modified = now()" . ($created ? ", created = {$created}" : ''), "id = {$id}"); if (!$rs) { // Update failed, rollback name. if (isset($old_path) && shift_uploaded_file($new_path, $old_path) === false) { file_list(array(gTxt('file_unsynchronized', array('{name}' => $filename)), E_ERROR)); return; } else { file_list(array(gTxt('file_not_updated', array('{name}' => $filename)), E_ERROR)); return; } } update_lastmod('file_saved', compact('id', 'filename', 'title', 'category', 'description', 'status', 'size')); file_list(gTxt('file_updated', array('{name}' => $filename))); }
function image_save() { global $txp_user; $varray = array_map('assert_string', gpsa(array('id', 'name', 'category', 'caption', 'alt'))); extract(doSlash($varray)); $id = $varray['id'] = assert_int($id); $author = fetch('author', 'txp_image', 'id', $id); if (!has_privs('image.edit') && !($author === $txp_user && has_privs('image.edit.own'))) { image_list(gTxt('restricted_area')); return; } $constraints = array('category' => new CategoryConstraint(gps('category'), array('type' => 'image'))); callback_event_ref('image_ui', 'validate_save', 0, $varray, $constraints); $validator = new Validator($constraints); if ($validator->validate() && safe_update("txp_image", "name = '{$name}',\n category = '{$category}',\n alt = '{$alt}',\n caption = '{$caption}'", "id = {$id}")) { $message = gTxt('image_updated', array('{name}' => doStrip($name))); update_lastmod(); } else { $message = array(gTxt('image_save_failed'), E_ERROR); } image_list($message); }
/** * Renders a widget to select various amounts to page lists by. * * The rendered options can be changed via a '{$event}_ui > pageby_values' * callback event. * * @param string $event Event * @param int $val Current setting * @param string|null $step Step * @return string HTML */ function pageby_form($event, $val, $step = null) { $vals = array(15, 25, 50, 100); callback_event_ref($event . '_ui', 'pageby_values', 0, $vals); if ($step === null) { $step = $event . '_change_pageby'; } $out = array(); foreach ($vals as $qty) { if ($qty == $val) { $class = 'navlink-active'; $aria_pressed = 'true'; } else { $class = 'navlink'; $aria_pressed = 'false'; } $out[] = href($qty, array('event' => $event, 'step' => $step, 'qty' => $qty, '_txp_token' => form_token()), array('class' => $class, 'title' => gTxt('view_per_page', array('{page}' => $qty)), 'aria-pressed' => $aria_pressed, 'role' => 'button')); } return graf(join('', $out), array('class' => 'nav-tertiary pageby')); }
/** * Return a list of status codes and their associated names. * * The list can be extended with a 'status.types > types' callback event. * Callback functions get passed three arguments: '$event', '$step' and * '$status_list'. The third parameter contains a reference to an array of * 'status_code => label' pairs. * * @param bool Return the list with L10n labels (for UI purposes) or raw values (for comparisons) * @param array List of status keys (numbers) to exclude * @return array A status array * @since 4.6.0 */ function status_list($labels = true, $exclude = array()) { $status_list = array(STATUS_DRAFT => 'draft', STATUS_HIDDEN => 'hidden', STATUS_PENDING => 'pending', STATUS_LIVE => 'live', STATUS_STICKY => 'sticky'); if (!is_array($exclude)) { $exclude = array(); } foreach ($exclude as $remove) { unset($status_list[(int) $remove]); } callback_event_ref('status.types', 'types', 0, $status_list); if ($labels) { $status_list = array_map('gTxt', $status_list); } return $status_list; }