diff --git a/src/configs/Config.php b/src/configs/Config.php index 53ccfbb06..adb96f771 100755 --- a/src/configs/Config.php +++ b/src/configs/Config.php @@ -1264,6 +1264,15 @@ nsdefine('NUM_FIELD_LEN', 4); nsdefine('WRITING_MODE_LEN', 5); /** Max user session size */ nsdefine('MAX_USER_SESSION_SIZE', 16384); +/* + * Wiki forms related + */ +/** Max size of CSV associated with a user created wiki form */ +nsconddefine('MAX_WIKI_FORM_CSV_SIZE', 5000000); +/** Max number of fields that a user created wiki form can have */ +nsconddefine('MAX_WIKI_FORM_FIELDS', 50); +/** Name to use for csv resource associated with a wiki form page */ +nsconddefine('WIKI_FORM_CSV_FILE', "form_data.csv"); /* * Adjustable CHAT BOT RELATED defines */ diff --git a/src/controllers/Controller.php b/src/controllers/Controller.php index 147d559b7..5d2e1a439 100755 --- a/src/controllers/Controller.php +++ b/src/controllers/Controller.php @@ -634,18 +634,22 @@ abstract class Controller * matches the given user and has not expired (1 hour till expires) * * @param string $token_name attribute of $_REQUEST containing CSRFToken - * @param string $user user id + * @param string $user_id user id of the user to check the token for + * @param bool $use_name_as_passed whether to use $token_name as the + * token (if true) or to use $_REQUEST[$token_name] * @return bool whether the CSRF token was valid */ - public function checkCSRFToken($token_name, $user) + public function checkCSRFToken($token_name, $user_id, + $use_name_as_passed = false) { $token_okay = false; - if (isset($_REQUEST[$token_name]) && - strlen($_REQUEST[$token_name]) == 22) { - $token_parts = explode("*", $_REQUEST[$token_name]); + $token_value = ($use_name_as_passed) ? $token_name : + $_REQUEST[$token_name] ?? ""; + if (strlen($token_value) == 22) { + $token_parts = explode("*", $token_value); if (isset($token_parts[1]) && $token_parts[1] + C\ONE_HOUR > time() && - L\crawlHash($user . $token_parts[1] . C\AUTH_KEY) == + L\crawlHash($user_id . $token_parts[1] . C\AUTH_KEY) == $token_parts[0]) { $token_okay = true; } @@ -715,6 +719,37 @@ abstract class Controller } return $timestamp; } + /** + * Sets up the graphical captcha view + * Draws the string for graphical captcha + * + * @param array &$data used by view to draw any dynamic content + * in this case we append a field "CAPTCHA_IMAGE" with a data + * url of the captcha to draw. + */ + public function setupGraphicalCaptchaViewData(&$data) + { + if (empty($_SESSION)) { + $_SESSION = []; + } + unset($_SESSION["captcha_text"]); + // defines captcha text + $characters_for_captcha = '123456789abcdefghijklmnpqrstuvwxyz'. + 'ABCDEFGHIJKLMNPQRSTUVWXYZ'; + $len = strlen($characters_for_captcha); + // selecting letters for captcha + $captcha_letter = $characters_for_captcha[rand(0, $len - 1)]; + $word = ""; + for ($i = 0; $i < C\CAPTCHA_LEN; $i++) { + // selecting letters for captcha + $captcha_letter = $characters_for_captcha[rand(0, $len - 1)]; + $word = $word . $captcha_letter; + } + // stores the captcha in a session variable 'captcha_text' + $_SESSION['captcha_text'] = $word; + $data["CAPTCHA_IMAGE"] = + $this->model("captcha")->makeGraphicalCaptcha($word); + } /** * Used to clean strings that might be tainted as originate from the user * diff --git a/src/controllers/RegisterController.php b/src/controllers/RegisterController.php index 0dc1d5df9..6e8e34128 100755 --- a/src/controllers/RegisterController.php +++ b/src/controllers/RegisterController.php @@ -826,37 +826,6 @@ class RegisterController extends Controller implements CrawlConstants } return $data; } - /** - * Sets up the graphical captcha view - * Draws the string for graphical captcha - * - * @param array &$data used by view to draw any dynamic content - * in this case we append a field "CAPTCHA_IMAGE" with a data - * url of the captcha to draw. - */ - public function setupGraphicalCaptchaViewData(&$data) - { - if (empty($_SESSION)) { - $_SESSION = []; - } - unset($_SESSION["captcha_text"]); - // defines captcha text - $characters_for_captcha = '123456789abcdefghijklmnpqrstuvwxyz'. - 'ABCDEFGHIJKLMNPQRSTUVWXYZ'; - $len = strlen($characters_for_captcha); - // selecting letters for captcha - $captcha_letter = $characters_for_captcha[rand(0, $len - 1)]; - $word = ""; - for ($i = 0; $i < C\CAPTCHA_LEN; $i++) { - // selecting letters for captcha - $captcha_letter = $characters_for_captcha[rand(0, $len - 1)]; - $word = $word . $captcha_letter; - } - // stores the captcha in a session variable 'captcha_text' - $_SESSION['captcha_text'] = $word; - $data["CAPTCHA_IMAGE"] = - $this->model("captcha")->makeGraphicalCaptcha($word); - } /** * Gets a list of translated recovery questions from the register view. * If insufficiently many questions have been translated for the current diff --git a/src/controllers/components/SocialComponent.php b/src/controllers/components/SocialComponent.php index bafd90b64..b17b77966 100644 --- a/src/controllers/components/SocialComponent.php +++ b/src/controllers/components/SocialComponent.php @@ -3438,6 +3438,11 @@ class SocialComponent extends Component implements CrawlConstants if ($data['MODE'] == "read") { $data['GROUP_STATUS'] = $group['STATUS']; $data['JUST_THREAD'] = true; + if ((!empty($_POST['RCSVFORM']) || !empty($_POST['CSVFORM'])) + && !empty($_POST[C\CSRF_TOKEN])) { + $this->processWikiFormData($data, $user_id, $group_id, + $sub_path); + } $this->initializeReadMode($data, $user_id, $group_id, $sub_path); } else if (in_array($data['MODE'], ['edit', 'source'])) { @@ -3461,7 +3466,8 @@ class SocialComponent extends Component implements CrawlConstants $data['settings'] = "false"; if (!empty($data['RESOURCE_NAME'])) { $name_parts = pathinfo($data['RESOURCE_NAME']); - if (!empty($name_parts['extension'])) { + if (!empty($name_parts['extension']) && + empty($data['RAW'])) { switch ($name_parts['extension']) { case 'csv': $user_config = ""; @@ -3560,6 +3566,118 @@ class SocialComponent extends Component implements CrawlConstants $this->updateGetWikiImpressionInfo($data, $user_id, $group_id); return $data; } + /** + * + * @param array &$data associative array of values to be echoed by the view + * @param int $user_id id of user requesting a wiki page + * @param int $group_id group in which wiki page belongs + * @param string $sub_path any path within wiki page folder for resources + */ + private function processWikiFormData($data, $user_id, $group_id, + $sub_path) + { + $parent = $this->parent; + $group_model = $parent->model("group"); + if (empty($data['PAGE_ID']) || empty($group_id)) { + return; + } + $user_id = $_SESSION['USER_ID'] ?? C\PUBLIC_USER_ID; + $default_folders = $group_model->getGroupPageResourcesFolders($group_id, + $data['PAGE_ID']); + $csv_filepath = $default_folders[0] . '/' . C\WIKI_FORM_CSV_FILE; + if (!$parent->checkCSRFToken($_POST[C\CSRF_TOKEN], $user_id, true)) { + return $parent->redirectWithMessage( + tl('social_component_page_data_expired'), + ['arg', 'page_name', 'settings', 'caret', 'scroll_top', 'sf']); + } + $tmp_page = preg_replace("/\[{form\-hash(.+?)}\]/", "[{form-hash}]", + $data['PAGE']); + $csv_form_hash = L\crawlHash(C\AUTH_KEY . $_POST[C\CSRF_TOKEN] . + L\crawlHash($tmp_page)); + if ($csv_form_hash != $_POST['CSV_FORM_HASH']) { + return $parent->redirectWithMessage( + tl('social_component_page_integrity_issue'), + ['arg', 'page_name', 'settings', 'caret', 'scroll_top', 'sf']); + } + $csv_headers = []; + if (empty($_POST['CSVFORM']['user_captcha_text'])) { + return $parent->redirectWithMessage( + tl('social_component_form_needs_captcha'), + ['arg', 'page_name', 'settings', 'caret', 'scroll_top', 'sf']); + } + $num_fields = count($_POST['CSVFORM'] ?? []) + + count($_POST['RCSVFORM'] ?? []); + if ($num_fields > C\MAX_WIKI_FORM_FIELDS) { + return $parent->redirectWithMessage( + tl('social_component_too_many_fields_form'), + ['arg', 'page_name', 'settings', 'caret', 'scroll_top', 'sf']); + } + $csv_form_info = [$_POST['CSVFORM'] ?? [] , $_POST['RCSVFORM'] ??[]]; + foreach ($csv_form_info as $csv_form_fields) { + foreach ($csv_form_fields as $form_field => $field_type) { + $form_field = substr( + $parent->clean($form_field, 'string'), 0, C\NAME_LEN); + if ($field_type == 'submit') { + } else if (in_array($form_field, $csv_headers)) { + continue; + } else { + $csv_headers[] = $form_field; + } + } + } + if (file_exists($csv_filepath)) { + if (filesize($csv_filepath) > C\MAX_WIKI_FORM_CSV_SIZE) { + return $parent->redirectWithMessage( + tl('social_component_csv_too_big'), ['arg', 'page_name', + 'settings', 'caret', 'scroll_top', 'sf']); + } + $fh = fopen($csv_filepath, "a+"); + } else { + $fh = fopen($csv_filepath, "w+"); + fputcsv($fh, $csv_headers); + } + $out_row = []; + foreach($csv_headers as $csv_header) { + $is_required = (isset($_POST['RCSVFORM'][$csv_header])) ? 1 : 0; + if ($is_required && empty($_POST[$csv_header])) { + return $parent->redirectWithMessage( + tl('social_component_fill_required_fields'), array_merge( + ['arg', 'page_name', 'settings', 'caret', 'scroll_top', + 'sf'], $csv_headers)); + } + if ($csv_header == 'user_captcha_text' && + (empty($_SESSION['captcha_text']) || + $_POST[$csv_header] != $_SESSION['captcha_text'])) { + $parent->model("visitor")->updateVisitor( + L\remoteAddress(), "captcha_time_out"); + return $parent->redirectWithMessage( + tl('social_component_captcha_failed'), array_merge( + ['arg', 'page_name', 'settings', 'caret', 'scroll_top', + 'sf'], $csv_headers)); + } + $header_type = $_POST['CSVFORM'][$csv_header] ?? "textfield"; + $clean_field = $parent->clean($_POST[$csv_header] ?? "", "string"); + if ($header_type == "submit") { + continue; + } else if ($header_type == "checkbox") { + $clean_field = empty($clean_field) ? false : true; + } else { + $max_lengths = [ + "radio" => C\NAME_LEN, + "textfield" => C\LONG_NAME_LEN, + "textarea" => C\TITLE_LEN + ]; + $clean_field = substr($clean_field, 0, + $max_lengths[$header_type]); + } + $out_row[] = $clean_field; + } + fputcsv($fh, $out_row); + fclose($fh); + return $parent->redirectWithMessage( + tl('social_component_choices_recorded'), ['arg', 'page_name', + 'settings', 'caret', 'scroll_top', 'sf']); + } /** * Sets up view variables for wiki pages when in read mode. If * a user send a command to indicate a media resource on a media list @@ -3654,6 +3772,9 @@ class SocialComponent extends Component implements CrawlConstants EOD; } } + if (strpos($data["PAGE"], "[{image-captcha}]") !== false) { + $parent->setupGraphicalCaptchaViewData($data); + } if (strpos($data["PAGE"], "spreadsheet_data") !== false) { if (!in_array("spreadsheet", $data["INCLUDE_SCRIPTS"])) { $data["INCLUDE_SCRIPTS"][] = "spreadsheet"; @@ -4057,9 +4178,12 @@ EOD; in_array($name_parts['extension'], ['csv', 'txt', 'tex', 'php', 'sql', 'html', 'java', 'py', 'pl', 'P', 'srt'])) { + $extension = $name_parts['extension']; + $data['RAW'] = !empty($_REQUEST['download']); $data['PAGE'] = $group_model->getPageResource( - $file_name, $group_id, $page_info['ID'], $sub_path); - if ($name_parts['extension'] != 'csv') { + $file_name, $group_id, $page_info['ID'], $sub_path, + $data['RAW']); + if (empty($data['RAW']) && $name_parts['extension'] != 'csv') { $data['PAGE'] = htmlentities($data['PAGE']); } } else { @@ -4230,6 +4354,12 @@ EOD; tl('social_component_page_created', $page_name), tl('social_component_page_discuss_here'), $read_address, $additional_substitutions); + if (empty($page_info['ID'])) { + return $parent->redirectWithMessage( + tl('social_component_page_not_saved'), + ['arg', 'page_name', 'settings', + 'caret', 'scroll_top', 'sf', "n"]); + } if ($set_path && !empty($page_info['ID'])) { $tmp = $group_model->getGroupPageResourcesFolders( $group_id, $page_info['ID'], "", true, false); @@ -4377,7 +4507,7 @@ EOD; } else if (isset($_REQUEST['resource_description'])) { $resource_description = $parent->clean( $_REQUEST['resource_description'], "string"); - if (!($resource_name = $parent->clean(urldecode($_REQUEST['n']?? ""), + if (!($resource_name = $parent->clean(urldecode($_REQUEST['n']??""), "file_name"))) { return $parent->redirectWithMessage( tl('social_component_resource_description_file_error'), @@ -4743,7 +4873,7 @@ EOD; if (substr($mime_type, 0, 4) == 'text') { $this->parent->recordViewSession($page_id, $sub_path, $media_name); } - if ($mime_type == "text/csv") { + if ($mime_type == "text/csv" && empty($data['RAW'])) { $data['INCLUDE_SCRIPTS'][] = 'spreadsheet'; $data['SPREADSHEET'] = true; } diff --git a/src/css/search.css b/src/css/search.css index aafa388a3..9be5756f4 100755 --- a/src/css/search.css +++ b/src/css/search.css @@ -3923,6 +3923,22 @@ td.instruct { max-width:100%; } +.html-ltr .wiki-resource-download +{ + height: 0; + float: right; + position:relative; + right: 30px; + top: -50px; +} +.html-rtl .wiki-resource-download +{ + height: 0; + float: left; + position:relative; + left: 30px; + top: -50px; +} .ebook, .wiki-resource-object { diff --git a/src/library/FetchUrl.php b/src/library/FetchUrl.php index 725b78556..0b09e3ea2 100755 --- a/src/library/FetchUrl.php +++ b/src/library/FetchUrl.php @@ -149,6 +149,9 @@ class FetchUrl implements CrawlConstants list($sites[$i][$key], $url, $headers, $dns_resolve, $referer) = self::prepareUrlHeaders($sites[$i][$key], $proxy_servers, $temp_dir, !$minimal); + if (empty($url)) { + continue; + } if ($headers == "gopher") { $is_gopher = true; $sites[$i][CrawlConstants::IS_GOPHER_URL] = $is_gopher; diff --git a/src/library/WikiParser.php b/src/library/WikiParser.php index 7af8cf546..d410c35d9 100644 --- a/src/library/WikiParser.php +++ b/src/library/WikiParser.php @@ -191,6 +191,51 @@ class WikiParser implements CrawlConstants ['/\r/', ""], ]; $braces_substitutions = [ + ["/{{username}}/si", + "<input type='hidden' name='username' value='[{username}]' />"], + ["/{{image-captcha\|(.+?)}}/si", "<div class='csv-captcha'>". + "<label for='captcha-id'>$1</label> [{image-captcha}]". + "<input id='captcha-id' type='text' name='user_captcha_text'/>". + "*</div><input type='hidden' name='CSVFORM[user_captcha_text]'. + value='textfield' />"], + ["/{{textfield\|(.+?)\|(.+?)}}/si", + "<label for='$2-id'>$1</label> <input id='$2-id' ". + "type='text' name='$2' value='[{csv-$2}]'>". + "<input type='hidden' name='CSVFORM[$2]' value='textfield' />"], + ["/{{r(?:equired)?-textfield\|(.+?)\|(.+?)}}/si", + "<label for='$2-id'>$1</label> <input id='$2-id' ". + "type='text' name='$2' value='[{csv-$2}]'>". + "<input type='hidden' name='CSVFORM[$2]' ". + "value='textfield' /><span clas='csv-star'>*</span>"], + ["/{{textarea\|(.+?)\|(.+?)}}/si", + "<label for='$2-id'>$1</label><br /><textarea id='$2-id' ". + "name='$2' class='short-text-area'>[{csv-$2}]</textarea>" . + "<input type='hidden' name='CSVFORM[$2]' value='textarea' />"], + ['/{{r(?:equired)?-textarea\|(.+?)\|(.+?)}}/si', + "<label for='$2-id'>$1</label><textarea id='$2-id' ". + "name='$2' class='short-text-area'>[{csv-$2}]</textarea>" . + "<input type='hidden' name='RCSVFORM[$2]' value='textarea' />". + "<span clas='csv-star'>*</span>"], + ["/{{checkbox\|(.+?)\|(.+?)}}/si", + "<label for='$2-id'>$1</label> <input id='$2-id' ". + "type='checkbox' name='$2' [{csv-checked-$2}] />". + "<input type='hidden' name='CSVFORM[$2]' value='checkbox' />"], + ["/{{r(?:equired)?-checkbox\|(.+?)\|(.+?)}}/si", + "<label for='$2-id'>$1</label> <input id='$2-id' ". + "type='checkbox' name='$2' [{csv-checked-$2}] />". + "<input type='hidden' name='RCSVFORM[$2]' value='checkbox' />"], + ["/{{radio\|(.+?)\|(.+?)\|(.+?)}}/si", + "<label for='$2-$3-id'>$1</label> <input id='$2-$3-id' ". + "type='radio' name='$2' value='$3' [{csv-checked-$2}] />". + "<input type='hidden' name='CSVFORM[$2]' value='radio' />"], + ["/{{r(?:equired)?-radio\|(.+?)\|(.+?)\|(.+?)}}/si", + "<label for='$2-$3-id'>$1</label> <input id='$2-$3-id' ". + "type='radio' name='$2' value='$3' [{csv-checked-$2}] />". + "<input type='hidden' name='RCSVFORM[$2]' value='radio' />". + "<span clas='csv-star'>*</span>"], + ["/{{submit\|(.+?)\|(.+?)}}/si", + "<input id='$2-id' type='submit' name='$1' value='$2' >". + "<input type='hidden' name='CSVFORM[$2]' value='submit' />"], ['/'.$not_paragraph.'{{\s*class\s*\=\s*'. ""([$class_or_id]+)"\s+(".$not_braces .")}}/", "$esc<span class=\"$1\" >\t\n$2$esc</span>\t"], diff --git a/src/models/GroupModel.php b/src/models/GroupModel.php index 28bf96d94..a53d27f99 100644 --- a/src/models/GroupModel.php +++ b/src/models/GroupModel.php @@ -1431,10 +1431,29 @@ class GroupModel extends Model implements MediaConstants if ($add_relationship_data) { $links_relationships = $parser->fetchLinks($page); } + $is_form = false; if ($this->getPageType($page) == 'share') { $parsed_page = $page; } else { + if (strstr($page, '{{submit|') !== false) { + $is_form = true; + } $parsed_page = $parser->parse($page); + if ($is_form && strstr($page, '<form ') !== false) { + return null; + } else if ($is_form) { + $end_head = "END_HEAD_VARS"; + $parsed_page = str_replace($end_head, $end_head . + "\n<form method='post' >\n<input type='hidden' name='" . + C\CSRF_TOKEN . "' value='[{just-token}]' />" . + "<input type='hidden' name='CSV_FORM_HASH' ". + "value='[{form-hash}]' />", $parsed_page); + $parsed_page .= "\n</form>\n"; + $page_body = explode("END_HEAD_VARS", $parsed_page, 2)[1]; + $parsed_page = preg_replace("/\[{form\-hash}\]/", + "[{form-hash". L\crawlHash($page_body) . "}]", + $parsed_page); + } } if ($page_id = $this->getPageId($group_id, $page_name, $locale_tag)) { //can only add and use resources for a page that exists @@ -2066,12 +2085,19 @@ class GroupModel extends Model implements MediaConstants for ($i = 0; $i < $num_matches; $i++) { $match_string = $matches[0][$i]; $resource_namespace_name = $matches[2][$i]; + if (empty($matches[1][$i])) { + $resource_namespace_name = urldecode($resource_namespace_name); + } $namespace_parts = explode(":", $resource_namespace_name, 2); if (count($namespace_parts) > 1 && $matches[1][$i] != "-qr") { - list($current_namespace, $resource_namespace_name) - = $namespace_parts; - $current_page_id = $this->getPageId($group_id, - $current_namespace, $locale_tag); + list($current_namespace, $resource_namespace_name) = + $namespace_parts; + if (empty($current_namespace)) { + $current_page_id = $page_id; + } else { + $current_page_id = $this->getPageId($group_id, + $current_namespace, $locale_tag); + } if ($current_page_id === false || $current_page_id === null) { continue; } @@ -2255,13 +2281,17 @@ class GroupModel extends Model implements MediaConstants "/scripts/epubjs-reader/reader/index.html")) { $epub_reader_url = C\SHORT_BASE_URL . "wd/scripts/epubjs-reader/reader/index.html"; + $replace_string = "<div class='wiki-resource-download'>". + "<a href='$resource_url' >⤓</a></div>"; $resource_url = urlencode($resource_url); $resource_url = "$epub_reader_url?bookPath=$resource_url"; - $replace_string = "<iframe class='wiki-resource-object' ". + $replace_string .= "<iframe class='wiki-resource-object' ". "src='$resource_url' >$resource_description</iframe>"; $parsed_page = preg_replace('/'.preg_quote($match_string, '/') .'/u', $replace_string, $parsed_page); } else if (in_array($mime_type, ['text/html', 'application/pdf'])) { + $replace_string = "<div class='wiki-resource-download'>". + "<a href='$resource_url' >⤓</a></div>"; $replace_string = "<iframe class='wiki-resource-object' ". "src='$resource_url' >$resource_description</iframe>"; $parsed_page = preg_replace('/'.preg_quote($match_string, '/') @@ -2328,7 +2358,10 @@ class GroupModel extends Model implements MediaConstants " spreadsheet_config = [];\n}\n". "spreadsheet_data[$i] = $resource_data;" . $spread_config . - "\n</script><div id='spreadsheet_$i'> </div>"; + "\n</script>". + "<div class='wiki-resource-download'><a href='$resource_url' >". + "⤓</a></div>". + "<div id='spreadsheet_$i'></div>"; $parsed_page = preg_replace('/' . preg_quote($match_string, '/') .'/u', $replace_string, $parsed_page, 1); @@ -3504,10 +3537,11 @@ EOD; * @param int $page_id identifier for page want copy a page resource for * @param string $sub_path subpath with the resource folder that should be * used to look up filename in + * @param bool $raw if csv file don't content to array of rows * @return string desired page resource */ public function getPageResource($file_name, $group_id, $page_id, - $sub_path = "") + $sub_path = "", $raw = false) { $folders = $this->getGroupPageResourcesFolders($group_id, $page_id, $sub_path); @@ -3517,7 +3551,7 @@ EOD; list($folder, $thumb_folder) = $folders; $contents = file_get_contents("$folder/$file_name"); $name_parts = pathinfo($file_name); - if (!empty($name_parts['extension']) && + if (!$raw && !empty($name_parts['extension']) && $name_parts['extension'] == 'csv') { $contents = json_encode(L\parseCsv($contents)); } diff --git a/src/scripts/spreadsheet.js b/src/scripts/spreadsheet.js index d640437d0..7ec668402 100644 --- a/src/scripts/spreadsheet.js +++ b/src/scripts/spreadsheet.js @@ -122,7 +122,7 @@ function Spreadsheet(spreadsheet_id, supplied_data) add_button = ""; pre_delete_button = ""; } - table += "<table border='1' >"; + table += "<table class='wikitable' >"; if (self.headings || self.mode == 'write') { table += "<tr><th></th>"; for (var i = 0; i < width; i++) { diff --git a/src/views/elements/WikiElement.php b/src/views/elements/WikiElement.php index 7b3acbf0a..699efac25 100644 --- a/src/views/elements/WikiElement.php +++ b/src/views/elements/WikiElement.php @@ -2115,6 +2115,37 @@ class WikiElement extends Element implements CrawlConstants $pre_page); $pre_page = preg_replace('/\[{token}\]/', $csrf_token, $pre_page); + $pre_page = preg_replace('/\[{just\-token}\]/', $data[C\CSRF_TOKEN], + $pre_page); + $pre_page = preg_replace('/\[{image-captcha}\]/', + "<img src='". ($data["CAPTCHA_IMAGE"] ?? "") ."' alt='captcha' />", + $pre_page); + $pre_page = preg_replace('/\[{username}\]/', + $_SESSION['USER_NAME'] ?? "PUBLIC_USER", $pre_page); + if (preg_match('/\[{form\-hash([^}]+)}\]/', $pre_page, + $hash_matches) != false) { + $page_hash = L\crawlHash(C\AUTH_KEY . $data[C\CSRF_TOKEN] . + $hash_matches[1]); + $pre_page = preg_replace('/\[{form-hash([^}]+)}\]/', $page_hash, + $pre_page); + if (preg_match_all('/\[{csv\-(.+)}\]/', $pre_page, + $csv_field_matches, PREG_SET_ORDER) > 0) { + foreach ($csv_field_matches as $csv_field_match) { + if (empty($csv_field_match[1])) { + continue; + } else if (substr($csv_field_match[1], 0, 8) == "checked-"){ + $csv_field_name = substr($csv_field_match[1], 8); + $replace = (empty($_REQUEST[$csv_field_name])) ? "" : + ' checked="checked" '; + } else { + $csv_field_name = $csv_field_match[1]; + $replace = $_REQUEST[$csv_field_name] ?? ""; + } + $pre_page = str_replace($csv_field_match[0], + $replace, $pre_page); + } + } + } if (stripos($pre_page, "[{recent_places}]") !== false) { ob_start(); $this->renderPath("", $data, [], "", "",