query( 'SHOW TABLE STATUS LIKE \''.$_DDATA['tbprefix'].'%\';' ); $err = $tableinfo->errorInfo(); if ($err[0] == '00000') { $tableinfo = $tableinfo->fetchAll(); foreach ($tableinfo as $table) { switch ($table['Name']) { case $_DDATA['tbprefix'].'config': $_RDATA['s_config_info'] = $table; break; case $_DDATA['tbprefix'].'crawldata': $_RDATA['s_crawldata_info'] = $table; break; case $_DDATA['tbprefix'].'query': $_RDATA['s_query_info'] = $table; } } } else $_SESSION['error'][] = 'Could not read search database status.'; // ***** Other runtime data $_RDATA['admin_pagination_options'] = array(25, 50, 100, 250, 500, 1000); if (!in_array($_ODATA['admin_index_pagination'], $_RDATA['admin_pagination_options'], true)) OS_setValue('admin_index_pagination', 100); $_RDATA['admin_pages'] = array( 'crawler' => 'Crawler', 'index' => 'Page Index', 'search' => 'Search' ); if ($_ODATA['s_limit_query_log']) $_RDATA['admin_pages']['queries'] = 'Query Log'; $_RDATA['index_status_list'] = array( '', 'OK', 'Orphan', 'Updated', 'Unlisted' ); // ***** Set session defaults if (empty($_SESSION['admin_page']) || empty($_RDATA['admin_pages'][$_SESSION['admin_page']])) $_SESSION['admin_page'] = 'crawler'; if (!isset($_SESSION['index_page'])) $_SESSION['index_page'] = 1; if (empty($_SESSION['index_filter_category'])) $_SESSION['index_filter_category'] = ''; if (empty($_SESSION['index_filter_status'])) $_SESSION['index_filter_status'] = ''; if (empty($_SESSION['index_filter_text'])) $_SESSION['index_filter_text'] = ''; if (empty($_SESSION['admin_username'])) $_SESSION['admin_username'] = ''; if (!$_SESSION['admin_username']) { // If we are logging in if ($_SERVER['REQUEST_METHOD'] == 'POST') { if (!empty($_POST['os_submit']) && $_POST['os_submit'] == 'os_admin_login') { if (empty($_POST['os_admin_username'])) $_POST['os_admin_username'] = ''; if (empty($_POST['os_admin_password'])) $_POST['os_admin_password'] = ''; if ($_POST['os_admin_username'] == $_RDATA['admin_username'] && $_POST['os_admin_password'] == $_RDATA['admin_password']) { $_SESSION['admin_username'] = $_RDATA['admin_username']; $_SESSION['admin_page'] = 'crawler'; header('Location: '.$_SERVER['REQUEST_URI']); exit(); } else $_SESSION['error'][] = 'Invalid username or password.'; } } } else { /* ***** Handle POST Requests ************************************** */ if ($_SERVER['REQUEST_METHOD'] == 'POST') { // JSON POST request // These are usually sent by javascript fetch() if ($_SERVER['CONTENT_TYPE'] == 'application/json') { $postBody = file_get_contents('php://input'); $_POST = json_decode($postBody, false); $response = array(); if (empty($_POST->action)) $_POST->action = ''; switch ($_POST->action) { // ***** Set the key for initiating the crawler case 'setkey': if (!$_ODATA['sp_crawling']) { $md5 = md5(hrtime(true)); OS_setValue('sp_key', $md5); OS_setValue('sp_log', ''); OS_setValue('sp_progress', array(0, 1, false)); $response = array( 'status' => 'Success', 'message' => 'Key set to initiate crawler', 'sp_key' => $md5 ); } else { $response = array( 'status' => 'Error', 'message' => 'Crawler is already running; current progress: '.$_ODATA['sp_progress'][0].' / '.$_ODATA['sp_progress'][1] ); } break; // ***** Download a text or csv file case 'download': if (empty($_POST->content)) $_POST->content = ''; switch ($_POST->content) { // Download a text file of the latest crawl log case 'crawl_log': if (!$_ODATA['sp_crawling']) { if ($_ODATA['sp_time_end']) { $lines = explode("\n", $_ODATA['sp_log']); if (empty($_POST->grep)) $_POST->grep = ''; switch ($_POST->grep) { case 'all': break; case 'errors': $lines = preg_grep('/^[\[\*]/', $lines); break; default: $lines = preg_grep('/^[\[\*\w\d]/', $lines); } if ($_POST->grep) $_POST->grep = '-'.$_POST->grep; header('Content-type: text/plain; charset='.strtolower($_ODATA['s_charset'])); header('Content-disposition: attachment; filename="'. 'crawl-log'.$_POST->grep.'_'.date('Y-m-d', $_ODATA['sp_time_end']).'.txt"'); // UTF-8 byte order mark if (strtolower($_ODATA['s_charset']) == 'utf-8') echo "\xEF\xBB\xBF"; die(implode("\n", $lines)); } else { $response = array( 'status' => 'Error', 'message' => 'Crawler has not run yet; no log to download' ); } } else { $response = array( 'status' => 'Error', 'message' => 'Currently crawling; try again later' ); } break; // Download a csv of the unfiltered page index case 'page_index': $pageIndex = $_DDATA['pdo']->query( 'SELECT `url`, `category`, `content_mime`, `content_charset`, `status`, `flag_unlisted`, `last_modified`, `priority` FROM `'.$_DDATA['tbprefix'].'crawldata` ORDER BY `url_sort`;'); $err = $pageIndex->errorInfo(); if ($err[0] == '00000') { $pageIndex = $pageIndex->fetchAll(); if (count($pageIndex)) { header('Content-type: text/csv; charset='.strtolower($_ODATA['s_charset'])); header('Content-disposition: attachment; filename="'. 'page-index_'.date('Y-m-d').'.csv"'); $output = fopen('php://output', 'w'); // UTF-8 byte order mark if (strtolower($_ODATA['s_charset']) == 'utf-8') fwrite($output, "\xEF\xBB\xBF"); $headings = array( 'URL', 'Category', 'MIME Type', 'Character Encoding', 'Status', 'Last Modified', 'Priority' ); fputcsv($output, $headings); foreach ($pageIndex as $line) { if ($line['flag_unlisted']) $line['status'] .= ' (Unlisted)'; unset($line['flag_unlisted']); $line['last_modified'] = date('c', $line['last_modified']); fputcsv($output, $line); } fclose($output); die(); } else { $response = array( 'status' => 'Error', 'message' => 'The page index is empty; nothing to download' ); } } else { $response = array( 'status' => 'Error', 'message' => 'Could not read the page index database' ); } break; // Download a csv of the complete query log case 'query_log': $queryLog = $_DDATA['pdo']->query( 'SELECT `query`, `results`, `stamp`, INET_NTOA(`ip`) AS `ipaddr` FROM `'.$_DDATA['tbprefix'].'query` ORDER BY `stamp` DESC;' ); $err = $queryLog->errorInfo(); if ($err[0] == '00000') { $queryLog = $queryLog->fetchAll(); if (count($queryLog)) { header('Content-type: text/csv; charset='.strtolower($_ODATA['s_charset'])); header('Content-disposition: attachment; filename="'. 'query-log_'.date('Y-m-d').'.csv"'); $output = fopen('php://output', 'w'); // UTF-8 byte order mark if (strtolower($_ODATA['s_charset']) == 'utf-8') fwrite($output, "\xEF\xBB\xBF"); $headings = array('Query', 'Results', 'Time Stamp', 'IP'); if ($_GEOIP2) $headings[] = 'Country'; fputcsv($output, $headings); foreach ($queryLog as $line) { $line['stamp'] = date('c', $line['stamp']); if ($_GEOIP2) { $line['country'] = ''; try { $geo = $_GEOIP2->country($line['ipaddr']); } catch(Exception $e) { $geo = false; } if (!empty($geo->raw['country']['names']['en'])) $line['country'] = $geo->raw['country']['names']['en']; } fputcsv($output, $line); } fclose($output); die(); } else { $response = array( 'status' => 'Error', 'message' => 'The query log is empty; nothing to download' ); } } else { $response = array( 'status' => 'Error', 'message' => 'Could not read the query log database' ); } break; default: $response = array( 'status' => 'Error', 'message' => 'Invalid content selected to download' ); } break; // ***** Not used? case 'fetch': if (empty($_POST->value)) $_POST->value = ''; if (!empty($_ODATA[$_POST->value])) { $response = array( 'status' => 'Success', 'message' => trim($_ODATA[$_POST->value]) ); } else { $response = array( 'status' => 'Error', 'message' => 'Invalid value selected to fetch' ); } } header('Content-type: application/json; charset='.strtolower($_ODATA['s_charset'])); die(json_encode($response, JSON_INVALID_UTF8_IGNORE)); // Normal POST request } else if (!empty($_POST['os_submit'])) { switch ($_POST['os_submit']) { // ***** Crawler >> Settings case 'os_sp_crawl_config': if (isset($_POST['os_sp_starting'])) { $_POST['os_sp_starting'] = str_replace("\r\n", "\n", trim($_POST['os_sp_starting'])); $_POST['os_sp_starting'] = preg_replace('/\n+/', "\n", $_POST['os_sp_starting']); $_POST['os_sp_starting'] = substr($_POST['os_sp_starting'], 0, 4095); $_POST['os_sp_starting'] = explode("\n", $_POST['os_sp_starting']); foreach ($_POST['os_sp_starting'] as $key => $starting) { $starting = preg_replace( '/#.*$/', '', filter_var( str_replace(' ', '%20', $starting), FILTER_SANITIZE_URL ) ); $_POST['os_sp_starting'][$key] = str_replace('%20', ' ', $starting); } $_POST['os_sp_starting'] = array_filter($_POST['os_sp_starting'], function($a) { return preg_match('/^(([^:\/?#]+):)(\/\/([^\/?#]+))([^?#]*)(\?([^#]*))?(#(.*))?/', $a); }); if (!count($_POST['os_sp_starting'])) { $_POST['os_sp_starting'][] = $_ODATA['admin_install_domain'].'/'; $_SESSION['error'][] = 'Cannot have an empty or invalid Starting URLs field.'; } OS_setValue('sp_starting', implode("\n", $_POST['os_sp_starting'])); } if (isset($_POST['os_sp_useragent'])) { $_POST['os_sp_useragent'] = filter_var($_POST['os_sp_useragent'], FILTER_SANITIZE_SPECIAL_CHARS); OS_setValue('sp_useragent', substr($_POST['os_sp_useragent'], 0, 255)); } if (isset($_POST['os_sp_cookies']) && $_POST['os_sp_cookies'] == '1') { $_POST['os_sp_cookies'] = 1; } else $_POST['os_sp_cookies'] = 0; OS_setValue('sp_cookies', $_POST['os_sp_cookies']); if (isset($_POST['os_sp_ifmodifiedsince']) && $_POST['os_sp_ifmodifiedsince'] == '1') { $_POST['os_sp_ifmodifiedsince'] = 1; } else $_POST['os_sp_ifmodifiedsince'] = 0; OS_setValue('sp_ifmodifiedsince', $_POST['os_sp_ifmodifiedsince']); if (isset($_POST['os_sp_autodelete']) && $_POST['os_sp_autodelete'] == '1') { $_POST['os_sp_autodelete'] = 1; } else $_POST['os_sp_autodelete'] = 0; OS_setValue('sp_autodelete', $_POST['os_sp_autodelete']); if (isset($_POST['os_sp_timeout_url'])) { $_POST['os_sp_timeout_url'] = max(1, min(65535, (int)$_POST['os_sp_timeout_url'])); OS_setValue('sp_timeout_url', (int)$_POST['os_sp_timeout_url']); } if (isset($_POST['os_sp_timeout_crawl'])) { $_POST['os_sp_timeout_crawl'] = max(1, min(65535, (int)$_POST['os_sp_timeout_crawl'])); OS_setValue('sp_timeout_crawl', (int)$_POST['os_sp_timeout_crawl']); } if (isset($_POST['os_sp_sleep'])) { $_POST['os_sp_sleep'] = max(0, min(65535, (int)$_POST['os_sp_sleep'])); OS_setValue('sp_sleep', (int)$_POST['os_sp_sleep']); } if (isset($_POST['os_sp_limit_crawl'])) { $_POST['os_sp_limit_crawl'] = max(1, min(65535, (int)$_POST['os_sp_limit_crawl'])); OS_setValue('sp_limit_crawl', (int)$_POST['os_sp_limit_crawl']); } if (isset($_POST['os_sp_limit_store'])) { $_POST['os_sp_limit_store'] = max(1, min(65535, (int)$_POST['os_sp_limit_store'])); OS_setValue('sp_limit_store', $_POST['os_sp_limit_store']); } if (isset($_POST['os_sp_limit_depth'])) { $_POST['os_sp_limit_depth'] = max(1, min(255, (int)$_POST['os_sp_limit_depth'])); OS_setValue('sp_limit_depth', (int)$_POST['os_sp_limit_depth']); } if (isset($_POST['os_sp_limit_filesize'])) { $_POST['os_sp_limit_filesize'] = max(1, min(65535, (int)$_POST['os_sp_limit_filesize'])); OS_setValue('sp_limit_filesize', (int)$_POST['os_sp_limit_filesize']); } if (isset($_POST['os_sp_require_url'])) { $_POST['os_sp_require_url'] = str_replace("\r\n", "\n", trim($_POST['os_sp_require_url'])); $_POST['os_sp_require_url'] = preg_replace('/\n+/', "\n", $_POST['os_sp_require_url']); $_POST['os_sp_require_url'] = substr($_POST['os_sp_require_url'], 0, 4095); $_POST['os_sp_require_url'] = explode("\n", $_POST['os_sp_require_url']); foreach ($_POST['os_sp_require_url'] as $key => $require) { if ($require[0] == '*') { $require = substr($require, 1); $test = preg_match('/'.str_replace('/', '\/', $require).'/', 'test'); if ($test === false) { $_SESSION['error'][] = 'Invalid regular expression in Require URL Match field \''.$require.'\' removed.'; unset($_POST['os_sp_require_url'][$key]); } } else $_POST['os_sp_require_url'][$key] = filter_var($require, FILTER_SANITIZE_URL); } OS_setValue('sp_require_url', implode("\n", $_POST['os_sp_require_url'])); } if (isset($_POST['os_sp_ignore_url'])) { $_POST['os_sp_ignore_url'] = str_replace("\r\n", "\n", trim($_POST['os_sp_ignore_url'])); $_POST['os_sp_ignore_url'] = preg_replace('/\n+/', "\n", $_POST['os_sp_ignore_url']); $_POST['os_sp_ignore_url'] = substr($_POST['os_sp_ignore_url'], 0, 4095); $_POST['os_sp_ignore_url'] = explode("\n", $_POST['os_sp_ignore_url']); foreach ($_POST['os_sp_ignore_url'] as $key => $ignore) { if ($ignore[0] == '*') { $ignore = substr($ignore, 1); $test = preg_match('/'.str_replace('/', '\/', $ignore).'/', 'test'); if ($test === false) { $_SESSION['error'][] = 'Invalid regular expression in Ignore URL Match field \''.$ignore.'\' removed.'; unset($_POST['os_sp_ignore_url'][$key]); } } else $_POST['os_sp_ignore_url'][$key] = filter_var($ignore, FILTER_SANITIZE_URL); } OS_setValue('sp_ignore_url', implode("\n", $_POST['os_sp_ignore_url'])); } if (isset($_POST['os_sp_ignore_ext'])) { $_POST['os_sp_ignore_ext'] = preg_replace( array('/[^\w\d\. _-]/', '/ {2,}/'), array('', ' '), trim($_POST['os_sp_ignore_ext']) ); OS_setValue('sp_ignore_ext', substr($_POST['os_sp_ignore_ext'], 0, 4095)); } if (isset($_POST['os_sp_category_default'])) { $_POST['os_sp_category_default'] = preg_replace(array('/\s/', '/ {2,}/'), ' ', trim($_POST['os_sp_category_default'])); $_POST['os_sp_category_default'] = preg_replace('/[^\w \d-]/', '', $_POST['os_sp_category_default']); if ($_POST['os_sp_category_default']) { OS_setValue('sp_category_default', substr($_POST['os_sp_category_default'], 0, 30)); } else $_SESSION['error'][] = 'Category names may only contain letters, numbers, spaces or dashes.'; } else $_SESSION['error'][] = 'Please supply a category name.'; if (isset($_POST['os_sp_ignore_css'])) { $_POST['os_sp_ignore_css'] = preg_replace( array('/[^\w\d\. #_:-]/', '/ {2,}/'), array('', ' '), trim($_POST['os_sp_ignore_css']) ); OS_setValue('sp_ignore_css', substr($_POST['os_sp_ignore_css'], 0, 4095)); } if (isset($_POST['os_sp_title_strip'])) { $_POST['os_sp_title_strip'] = str_replace("\r\n", "\n", trim($_POST['os_sp_title_strip'])); $_POST['os_sp_title_strip'] = preg_replace('/\n+/', "\n", $_POST['os_sp_title_strip']); $_POST['os_sp_title_strip'] = substr($_POST['os_sp_title_strip'], 0, 4095); $_POST['os_sp_title_strip'] = explode("\n", $_POST['os_sp_title_strip']); foreach ($_POST['os_sp_title_strip'] as $key => $title_strip) { if ($title_strip[0] == '*') { $title_strip = substr($title_strip, 1); $test = preg_match('/'.str_replace('/', '\/', $title_strip).'/', 'test'); if ($test === false) { $_SESSION['error'][] = 'Invalid regular expression in Remove Text from Titles field \''.$title_strip.'\' removed.'; unset($_POST['os_sp_title_strip'][$key]); } } else $_POST['os_sp_title_strip'][$key] = filter_var($title_strip, FILTER_SANITIZE_SPECIAL_CHARS); } OS_setValue('sp_title_strip', implode("\n", $_POST['os_sp_title_strip'])); } $_SESSION['message'][] = 'Crawl settings have been saved.'; break; // ***** Crawler >> Administration case 'os_admin_config': if (isset($_POST['os_sp_interval'])) { $_POST['os_sp_interval'] = max(0, min(255, (int)$_POST['os_sp_interval'])); OS_setValue('sp_interval', (int)$_POST['os_sp_interval']); } if (isset($_POST['os_sp_interval_start'])) { if (preg_match('/\d\d:\d\d(:\d\d)?/', $_POST['os_sp_interval_start'])) { OS_setValue('sp_interval_start', $_POST['os_sp_interval_start']); } else $_SESSION['error'][] = 'Unexpected start time format.'; } if (isset($_POST['os_sp_interval_stop'])) { if (preg_match('/\d\d:\d\d(:\d\d)?/', $_POST['os_sp_interval_stop'])) { OS_setValue('sp_interval_stop', $_POST['os_sp_interval_stop']); } else $_SESSION['error'][] = 'Unexpected stop time format.'; } if (isset($_POST['os_sp_timezone'])) if (in_array($_POST['os_sp_timezone'], timezone_identifiers_list(), true)) OS_setValue('sp_timezone', $_POST['os_sp_timezone']); if (isset($_POST['os_sp_email_success']) && $_POST['os_sp_email_success'] == '1') { $_POST['os_sp_email_success'] = 1; } else $_POST['os_sp_email_success'] = 0; OS_setValue('sp_email_success', $_POST['os_sp_email_success']); if (isset($_POST['os_sp_email_failure']) && $_POST['os_sp_email_failure'] == '1') { $_POST['os_sp_email_failure'] = 1; } else $_POST['os_sp_email_failure'] = 0; OS_setValue('sp_email_failure', $_POST['os_sp_email_failure']); if (isset($_POST['os_admin_email'])) { if ($_MAIL) { $_POST['os_admin_email'] = str_replace("\r\n", "\n", $_POST['os_admin_email']); $_POST['os_admin_email'] = preg_replace('/\n+/', "\n", $_POST['os_admin_email']); $_POST['os_admin_email'] = substr($_POST['os_admin_email'], 0, 4095); $_POST['os_admin_email'] = explode("\n", $_POST['os_admin_email']); foreach ($_POST['os_admin_email'] as $key => $admin_email) { $email = $_MAIL->parseAddresses($admin_email); if (count($email)) { if ($email[0]['name']) { $_POST['os_admin_email'][$key] = $email[0]['name'].' <'.$email[0]['address'].'>'; } else $_POST['os_admin_email'][$key] = $email[0]['address']; } else { $_SESSION['error'][] = 'Invalid To: email address \''.$admin_email.'\'.'; unset($_POST['os_admin_email'][$key]); } } OS_setValue('admin_email', implode("\n", array_values($_POST['os_admin_email']))); } else $_SESSION['error'][] = 'PHPMailer needs to be installed to parse new email addresses.'; } $_SESSION['message'][] = 'Crawl administration settings have been saved.'; break; // ***** Crawler >> Sitemap case 'os_sp_sitemap_config': if (isset($_POST['os_sp_sitemap_file'])) { $_POST['os_sp_sitemap_file'] = substr($_POST['os_sp_sitemap_file'], 0, 255); $_POST['os_sp_sitemap_file'] = filter_var($_POST['os_sp_sitemap_file'], FILTER_SANITIZE_URL); if ($_POST['os_sp_sitemap_file']) { if (preg_match('/\.xml(\.gz)?$/', $_POST['os_sp_sitemap_file'])) { OS_setValue('sp_sitemap_file', $_POST['os_sp_sitemap_file']); } else $_SESSION['error'][] = 'Sitemap filename must end witn .xml or .xml.gz'; } else OS_setValue('sp_sitemap_file', ''); } if (isset($_POST['os_sp_sitemap_hostname'])) { $_POST['os_sp_sitemap_hostname'] = filter_var($_POST['os_sp_sitemap_hostname'], FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME); if ($_POST['os_sp_sitemap_hostname']) { OS_setValue('sp_sitemap_hostname', $_POST['os_sp_sitemap_hostname']); } else $_SESSION['error'][] = 'Invalid sitemap hostname.'; } $_SESSION['message'][] = 'Sitemap settings have been saved.'; break; // ***** Page Index >> With Selected... case 'os_index_with_selected': if (empty($_POST['os_index_pages'])) $_POST['os_index_pages'] = array(); if (is_array($_POST['os_index_pages'])) { $checksums_good = true; foreach ($_POST['os_index_pages'] as $key => $content_checksum) { $content_checksum = base64_decode($content_checksum); if ($content_checksum && strlen($content_checksum) == 20) { $_POST['os_index_pages'][$key] = $content_checksum; } else $checksums_good = false; } if ($checksums_good) { if (empty($_POST['os_index_select_action'])) $_POST['os_index_select_action'] = ''; switch ($_POST['os_index_select_action']) { case 'delete': $delete = $_DDATA['pdo']->prepare( 'DELETE FROM `'.$_DDATA['tbprefix'].'crawldata` WHERE `content_checksum`=:content_checksum;' ); foreach ($_POST['os_index_pages'] as $content_checksum) { $delete->execute(array('content_checksum' => $content_checksum)); $err = $delete->errorInfo(); if ($err[0] != '00000') { $_SESSION['error'][] = 'Database error on attempt to delete: '.$err[2]; break; } } // Refresh the sp_domains data since we deleted some rows $domainList = array(); $urls = $_DDATA['pdo']->query( 'SELECT `url` FROM `'.$_DDATA['tbprefix'].'crawldata`;' ); $err = $urls->errorInfo(); if ($err[0] == '00000') { $urls = $urls->fetchAll(); foreach ($urls as $url) { $url = parse_url($url['url']); if (is_array($url)) { $domain = $url['scheme'].'://'.$url['host']; if (!isset($domainList[$domain])) { $domainList[$domain] = 1; } else $domainList[$domain]++; } } OS_setValue('sp_domains', $domainList); } else $_SESSION['error'][] = 'Could not read domain count data from search database: '.$err[2]; break; case 'category': if (!empty($_POST['os_apply_new_category'])) { $_POST['os_apply_new_category'] = preg_replace(array('/\s/', '/ {2,}/'), ' ', trim($_POST['os_apply_new_category'])); $_POST['os_apply_new_category'] = preg_replace('/[^\w \d-]/', '', $_POST['os_apply_new_category']); $_POST['os_apply_new_category'] = substr($_POST['os_apply_new_category'], 0, 30); if ($_POST['os_apply_new_category']) { $update = $_DDATA['pdo']->prepare( 'UPDATE `'.$_DDATA['tbprefix'].'crawldata` SET `category`=:category WHERE `content_checksum`=:content_checksum;' ); foreach ($_POST['os_index_pages'] as $content_checksum) { $update->execute(array( 'category' => $_POST['os_apply_new_category'], 'content_checksum' => $content_checksum )); $err = $update->errorInfo(); if ($err[0] != '00000') { $_SESSION['error'][] = 'Database error on attempt to update category: '.$err[2]; break; } } $_SESSION['index_filter_category'] = ''; } else $_SESSION['error'][] = 'Category names may only contain letters, numbers, spaces or dashes.'; } else $_SESSION['error'][] = 'Please supply a category name.'; break; case 'priority': if (!empty($_POST['os_apply_new_priority'])) { $_POST['os_apply_new_priority'] = (float)$_POST['os_apply_new_priority']; $_POST['os_apply_new_priority'] = max(0, min(1, $_POST['os_apply_new_priority'])); $_POST['os_apply_new_priority'] = round($_POST['os_apply_new_priority'], 5); $update = $_DDATA['pdo']->prepare( 'UPDATE `'.$_DDATA['tbprefix'].'crawldata` SET `priority`=:priority WHERE `content_checksum`=:content_checksum;' ); foreach ($_POST['os_index_pages'] as $content_checksum) { $update->execute(array( 'priority' => $_POST['os_apply_new_priority'], 'content_checksum' => $content_checksum )); $err = $update->errorInfo(); if ($err[0] != '00000') { $_SESSION['error'][] = 'Database error on attempt to update priority: '.$err[2]; break; } } } else $_SESSION['error'][] = 'Please supply a priority value.'; break; case 'unlisted': $update = $_DDATA['pdo']->prepare( 'UPDATE `'.$_DDATA['tbprefix'].'crawldata` SET `flag_unlisted`=!`flag_unlisted` WHERE `content_checksum`=:content_checksum;' ); foreach ($_POST['os_index_pages'] as $content_checksum) { $update->execute(array('content_checksum' => $content_checksum)); $err = $update->errorInfo(); if ($err[0] != '00000') { $_SESSION['error'][] = 'Database error on attempt to toggle \'unlisted\' status: '.$err[2]; break; } } break; default: $_SESSION['error'][] = 'Unknown command.'; } } else $_SESSION['error'][] = 'Bad page checksum(s) given by user.'; } else $_SESSION['error'][] = 'Badly formed list of pages; could not perform an action.'; break; // ***** Page Index >> Text Match filter case 'os_index_filter_text': if (empty($_POST['os_index_filter_text'])) $_POST['os_index_filter_text'] = ''; $_POST['os_index_filter_text'] = filter_var($_POST['os_index_filter_text'], FILTER_SANITIZE_URL); $_SESSION['index_filter_text'] = $_POST['os_index_filter_text']; $_SESSION['index_page'] = 1; break; // ***** Search >> Search Settings case 'os_s_search_config': if (isset($_POST['os_s_limit_query'])) { $_POST['os_s_limit_query'] = max(1, min(255, (int)$_POST['os_s_limit_query'])); OS_setValue('s_limit_query', (int)$_POST['os_s_limit_query']); } if (isset($_POST['os_s_limit_terms'])) { $_POST['os_s_limit_terms'] = max(1, min(255, (int)$_POST['os_s_limit_terms'])); OS_setValue('s_limit_terms', (int)$_POST['os_s_limit_terms']); } if (isset($_POST['os_s_limit_term_length'])) { $_POST['os_s_limit_term_length'] = max(1, min(255, (int)$_POST['os_s_limit_term_length'])); OS_setValue('s_limit_term_length', (int)$_POST['os_s_limit_term_length']); } if (!isset($_POST['os_s_weight_title'])) $_POST['os_s_weight_title'] = $_ODATA['s_weights']['title']; $_POST['os_s_weight_title'] = number_format(max(0, (float)$_POST['os_s_weight_title']), 1, '.', ''); if (!isset($_POST['os_s_weight_body'])) $_POST['os_s_weight_body'] = $_ODATA['s_weights']['body']; $_POST['os_s_weight_body'] = number_format(max(0, (float)$_POST['os_s_weight_body']), 1, '.', ''); if (!isset($_POST['os_s_weight_keywords'])) $_POST['os_s_weight_keywords'] = $_ODATA['s_weights']['keywords']; $_POST['os_s_weight_keywords'] = number_format(max(0, (float)$_POST['os_s_weight_keywords']), 1, '.', ''); if (!isset($_POST['os_s_weight_description'])) $_POST['os_s_weight_description'] = $_ODATA['s_weights']['description']; $_POST['os_s_weight_description'] = number_format(max(0, (float)$_POST['os_s_weight_description']), 1, '.', ''); if (!isset($_POST['os_s_weight_url'])) $_POST['os_s_weight_url'] = $_ODATA['s_weights']['url']; $_POST['os_s_weight_url'] = number_format(max(0, (float)$_POST['os_s_weight_url']), 1, '.', ''); if (!isset($_POST['os_s_weight_multi'])) $_POST['os_s_weight_multi'] = $_ODATA['s_weights']['multi']; $_POST['os_s_weight_multi'] = number_format(max(0, (float)$_POST['os_s_weight_multi']), 1, '.', ''); if (!isset($_POST['os_s_weight_important'])) $_POST['os_s_weight_important'] = $_ODATA['s_weights']['important']; $_POST['os_s_weight_important'] = number_format(max(0, (float)$_POST['os_s_weight_important']), 1, '.', ''); if (!isset($_POST['os_s_weight_css_value'])) $_POST['os_s_weight_css_value'] = $_ODATA['s_weights']['css_value']; $_POST['os_s_weight_css_value'] = number_format(max(0, (float)$_POST['os_s_weight_css_value']), 1, '.', ''); OS_setValue('s_weights', array( 'title' => $_POST['os_s_weight_title'], 'body' => $_POST['os_s_weight_body'], 'keywords' => $_POST['os_s_weight_keywords'], 'description' => $_POST['os_s_weight_description'], 'css_value' => $_POST['os_s_weight_css_value'], 'url' => $_POST['os_s_weight_url'], 'multi' => $_POST['os_s_weight_multi'], 'important' => $_POST['os_s_weight_important'] )); if (isset($_POST['os_s_weight_css'])) { $_POST['os_s_weight_css'] = preg_replace( array('/[^\w\d\. #_:-]/', '/ {2,}/'), array('', ' '), trim($_POST['os_s_weight_css']) ); OS_setValue('s_weight_css', substr($_POST['os_s_weight_css'], 0, 4095)); } if (isset($_POST['os_s_charset'])) { $_POST['os_s_charset'] = substr($_POST['os_s_charset'], 0, 63); $_POST['os_s_charset'] = preg_replace('/[^\w\d\.:_-]/', '', $_POST['os_s_charset']); OS_setValue('s_charset', $_POST['os_s_charset']); } if (isset($_POST['os_s_limit_results'])) { $_POST['os_s_limit_results'] = max(1, min(255, (int)$_POST['os_s_limit_results'])); OS_setValue('s_limit_results', (int)$_POST['os_s_limit_results']); } if (isset($_POST['os_s_results_pagination'])) { $_POST['os_s_results_pagination'] = max(1, min(255, (int)$_POST['os_s_results_pagination'])); OS_setValue('s_results_pagination', (int)$_POST['os_s_results_pagination']); } if (isset($_POST['os_s_limit_matchtext'])) { $_POST['os_s_limit_matchtext'] = max(1, min(65535, (int)$_POST['os_s_limit_matchtext'])); OS_setValue('s_limit_matchtext', $_POST['os_s_limit_matchtext']); } if (isset($_POST['os_s_show_orphans']) && $_POST['os_s_show_orphans'] == '1') { $_POST['os_s_show_orphans'] = 1; } else $_POST['os_s_show_orphans'] = 0; OS_setValue('s_show_orphans', $_POST['os_s_show_orphans']); if (isset($_POST['os_s_show_filetype_html']) && $_POST['os_s_show_filetype_html'] == '1') { $_POST['os_s_show_filetype_html'] = 1; } else $_POST['os_s_show_filetype_html'] = 0; OS_setValue('s_show_filetype_html', $_POST['os_s_show_filetype_html']); $_SESSION['message'][] = 'Search settings have been saved.'; break; // ***** Search >> Search Template case 'os_s_search_template': if (isset($_POST['os_s_result_template'])) { $_POST['os_s_result_template'] = str_replace("\r", '', $_POST['os_s_result_template']); OS_setValue('s_result_template', substr($_POST['os_s_result_template'], 0, 65535)); $_SESSION['message'][] = 'Search result template updated.'; } break; // ***** Search >> Search Result Cache case 'os_s_cache_config': if (isset($_POST['os_s_limit_query_log'])) { $_POST['os_s_limit_query_log'] = max(0, min(255, (int)$_POST['os_s_limit_query_log'])); OS_setValue('s_limit_query_log', $_POST['os_s_limit_query_log']); } if (isset($_POST['os_s_limit_cache'])) { $_POST['os_s_limit_cache'] = max(0, min(65535, (int)$_POST['os_s_limit_cache'])); OS_setValue('s_limit_cache', $_POST['os_s_limit_cache']); } break; // ***** Search >> Search Result Purge case 'os_s_cache_purge': $purge = $_DDATA['pdo']->query( 'UPDATE `'.$_DDATA['tbprefix'].'query` SET `cache`=\'\';' ); $err = $purge->errorInfo(); if ($err[0] == '00000') { $_RDATA['s_cache_size'] = 0; $_SESSION['message'][] = 'Search result cache has been purged.'; } else $_SESSION['error'][] = 'Could not purge search result cache.'; break; // ***** Search >> Offline Javascript case 'os_jw_config': // ***** Search >> Write Offline Javascript case 'os_jw_write': if (isset($_POST['os_jw_hostname'])) { $_POST['os_jw_hostname'] = filter_var($_POST['os_jw_hostname'], FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME); if ($_POST['os_jw_hostname']) { OS_setValue('jw_hostname', $_POST['os_jw_hostname']); } else $_SESSION['error'][] = 'Invalid sitemap hostname.'; } if (isset($_POST['os_jw_compression'])) { $_POST['os_jw_compression'] = max(0, min(100, (int)$_POST['os_jw_compression'])); OS_setValue('jw_compression', (int)$_POST['os_jw_compression']); } if ($_POST['os_submit'] == 'os_jw_config') { $_SESSION['message'][] = 'Offline javascript search settings have been saved.'; break; } // ***** Write to and download the Offline Javascript file $crawldata = $_DDATA['pdo']->query( 'SELECT `url`, `title`, `description`, `keywords`, `category`, `content_mime`, `weighted`, `content`, `priority` FROM `'.$_DDATA['tbprefix'].'crawldata` WHERE `flag_unlisted`=0 '.$_RDATA['s_show_orphans'].' AND `url` LIKE \''.addslashes($_ODATA['jw_hostname']).'/%\';' ); $err = $crawldata->errorInfo(); if ($err[0] == '00000') { $crawldata = $crawldata->fetchAll(); // If compression value is less than 100 then get a word // list frequency report from all indexed pages if ($_ODATA['jw_compression'] < 100) { $words = array(); foreach ($crawldata as $key => $row) { $crawldata[$key]['words'] = array_unique(explode(' ', $row['content'])); foreach ($crawldata[$key]['words'] as $index => $word) { if ($word) { if (empty($words[$word])) { $words[$word] = 1; } else $words[$word]++; } } } // Use the word frequency report to create a filter of // words that are more common than the compression // threshold $compressionFilter = array(); Foreach ($words as $word => $count) if (($count / count($crawldata)) * 100 >= $_ODATA['jw_compression']) $compressionFilter[] = $word; } $repStr = '/^'.preg_quote($_ODATA['jw_hostname'], '/').'/'; foreach ($crawldata as $key => $row) { // Use the compression filter to remove all of the most // common words from the content of this page if ($_ODATA['jw_compression'] < 100) { $crawldata[$key]['words'] = array_diff($row['words'], $compressionFilter); $crawldata[$key]['words'] = implode(' ', $crawldata[$key]['words']); } else $crawldata[$key]['words'] = $row['content']; // Remove the common domain from all URLs $crawldata[$key]['url'] = preg_replace($repStr, '', $row['url']); // Format non-.html filenames into .html ones if ($row['content_mime'] == 'text/html') { $rq = explode('?', $crawldata[$key]['url'], 2); if ($rq[0] == '' || $rq[0][strlen($rq[0]) - 1] == '/') $rq[0] .= 'index.html'; if (!preg_match('/\.html?$/', $rq[0])) $rq[0] .= '.html'; $crawldata[$key]['url'] = implode('?', $rq); } foreach ($crawldata[$key] as $prop => $value) if (is_string($value)) $crawldata[$key][$prop] = addslashes($value); } // Use this for dodgy character check on javascript output // [^\w\s()\[\]{};:.‖‘’‟„…/@©~®§⇔⇕⇒⇨⇩↪&\\^<>›×™*·,±_²°|≥!#$¢£+≤=•«%½»?`"'-] header('Content-type: text/javascript; charset='.strtolower($_ODATA['s_charset'])); header('Content-disposition: attachment; filename="offline-search.js"'); // Populate the offline javascript Mustache template require_once __DIR__.'/mustache/src/Mustache/Autoloader.php'; Mustache_Autoloader::register(); $output = new Mustache_Engine(array('entity_flags' => ENT_QUOTES)); die(mb_convert_encoding( $output->render( file_get_contents(__DIR__.'/js/template.offline.js'), array( 'version' => $_ODATA['version'], 'date' => date('r'), 'sp_punct' => json_encode($_RDATA['sp_punct'], JSON_INVALID_UTF8_IGNORE), 's_latin' => json_encode($_RDATA['s_latin'], JSON_INVALID_UTF8_IGNORE), 's_filetypes' => json_encode($_RDATA['s_filetypes'], JSON_INVALID_UTF8_IGNORE), 's_category_list' => json_encode($_RDATA['s_category_list'], JSON_INVALID_UTF8_IGNORE), 'jw_compression' => $_ODATA['jw_compression'], 's_limit_query' => $_ODATA['s_limit_query'], 's_limit_terms' => $_ODATA['s_limit_terms'], 's_limit_term_length' => $_ODATA['s_limit_term_length'], 's_limit_matchtext' => $_ODATA['s_limit_matchtext'], 's_show_filetype_html' => $_ODATA['s_show_filetype_html'], 's_results_pagination' => $_ODATA['s_results_pagination'], 's_limit_results' => $_ODATA['s_limit_results'], 's_result_template' => json_encode(preg_replace('/\s{2,}/', ' ', $_ODATA['s_result_template']), JSON_INVALID_UTF8_IGNORE), 's_weights' => json_encode($_ODATA['s_weights'], JSON_INVALID_UTF8_IGNORE), 'os_crawldata' => $crawldata ) ), 'UTF-8', $_ODATA['s_charset'] )); } else $_SESSION['error'][] = 'Error reading from the search result database: '.$err[2]; break; // ***** Unknown 'os_submit' command default: header('Content-type: text/plain; charset='.strtolower($_ODATA['s_charset'])); var_dump($_POST); exit(); } header('Location: '.$_SERVER['REQUEST_URI']); exit(); // Normal POST request, but without 'os_submit' // These are usually triggered by a javascript form.submit() } else { // Set new Page Index pagination value if (!empty($_POST['os_index_hidden_pagination'])) { $_POST['os_index_hidden_pagination'] = (int)$_POST['os_index_hidden_pagination']; if (in_array($_POST['os_index_hidden_pagination'], $_RDATA['admin_pagination_options'], true)) { OS_setValue('admin_index_pagination', $_POST['os_index_hidden_pagination']); $_SESSION['index_page'] = 1; } header('Location: '.$_SERVER['REQUEST_URI']); exit(); } // Select a Page Index Category filter if (!empty($_POST['os_index_new_filter_category'])) { if (!empty($_RDATA['s_category_list'][$_POST['os_index_new_filter_category']])) { $_SESSION['index_filter_category'] = $_POST['os_index_new_filter_category']; $_SESSION['index_page'] = 1; } header('Location: '.$_SERVER['REQUEST_URI']); exit(); } // Select a Page Index Status filter if (!empty($_POST['os_index_new_filter_status'])) { if (in_array($_POST['os_index_new_filter_status'], $_RDATA['index_status_list'], true)) { $_SESSION['index_filter_status'] = $_POST['os_index_new_filter_status']; $_SESSION['index_page'] = 1; } header('Location: '.$_SERVER['REQUEST_URI']); exit(); } // Unknown POST command header('Content-type: text/plain; charset='.strtolower($_ODATA['s_charset'])); var_dump($_POST); exit(); } // Select a new Administration UI page } else if (!empty($_GET['page'])) { if (!empty($_RDATA['admin_pages'][$_GET['page']])) $_SESSION['admin_page'] = $_GET['page']; // Select a new page within the Page Index list } else if (isset($_GET['ipage'])) { $_GET['ipage'] = (int)$_GET['ipage']; $_SESSION['index_page'] = $_GET['ipage']; // User has requested to log out } else if (isset($_GET['logout'])) { $_SESSION = array(); $_SESSION['message'][] = 'You have been logged out.'; header('Location: '.$_SERVER['REQUEST_URI']); exit(); } // Perform pre-processing SQL actions that may trigger // $_SESSION errors switch ($_SESSION['admin_page']) { case 'crawler': // Get list of domains from the starting URLs $_RDATA['sp_starting'] = array_filter(array_map('trim', explode("\n", $_ODATA['sp_starting']))); $_RDATA['s_starting_domains'] = array(); foreach ($_RDATA['sp_starting'] as $starting) { $starting = parse_url($starting); if (!empty($starting['host'])) $_RDATA['s_starting_domains'][] = $starting['host']; } $_RDATA['s_starting_domains'] = array_unique($_RDATA['s_starting_domains']); if (count($_RDATA['s_starting_domains']) == 1) OS_setValue('sp_sitemap_hostname', $_RDATA['s_starting_domains'][0]); break; case 'index': $_RDATA['page_index_rows'] = false; $_RDATA['page_index_found_rows'] = false; if ($_RDATA['s_crawldata_info']['Rows']) { // ***** Select rows to populate the Page Index table $indexRows = $_DDATA['pdo']->prepare( 'SELECT SQL_CALC_FOUND_ROWS `url`, `title`, `category`, `content_checksum`, `status`, `flag_unlisted`, `flag_updated`, `priority` FROM `'.$_DDATA['tbprefix'].'crawldata` WHERE (:text1=\'\' OR `url` LIKE :text2) AND (:category1=\'\' OR `category`=:category2) AND (:status1=\'\' OR `status`=:status2) AND (:flag_unlisted1=\'any\' OR `flag_unlisted`=:flag_unlisted2) AND (:flag_updated1=\'any\' OR `flag_updated`=:flag_updated2) ORDER BY `url_sort` LIMIT :offset, :pagination;' ); $text = ($_SESSION['index_filter_text']) ? trim($_SESSION['index_filter_text']) : ''; $category = ($_SESSION['index_filter_category'] != '') ? $_SESSION['index_filter_category'] : ''; if ($_SESSION['index_filter_status'] == 'OK' || $_SESSION['index_filter_status'] == 'Orphan') { $status = $_SESSION['index_filter_status']; } else $status = ''; $unlisted = ($_SESSION['index_filter_status'] == 'Unlisted') ? 1 : 'any'; $updated = ($_SESSION['index_filter_status'] == 'Updated') ? 1 : 'any'; $_RDATA['page_index_offset'] = ($_SESSION['index_page'] - 1) * $_ODATA['admin_index_pagination']; $indexRows->execute(array( 'text1' => $text, 'text2' => '%'.$text.'%', 'category1' => $category, 'category2' => $category, 'status1' => $status, 'status2' => $status, 'flag_unlisted1' => $unlisted, 'flag_unlisted2' => $unlisted, 'flag_updated1' => $updated, 'flag_updated2' => $updated, 'offset' => $_RDATA['page_index_offset'], 'pagination' => $_ODATA['admin_index_pagination'] )); $err = $indexRows->errorInfo(); if ($err[0] == '00000') { $_RDATA['page_index_rows'] = $indexRows->fetchAll(); $foundRows = $_DDATA['pdo']->query('SELECT FOUND_ROWS();'); $err = $foundRows->errorInfo(); if ($err[0] == '00000') { $foundRows = $foundRows->fetchAll(PDO::FETCH_NUM); if (count($foundRows)) { $_RDATA['page_index_found_rows'] = $foundRows[0][0]; $_RDATA['index_pages'] = ceil($_RDATA['page_index_found_rows'] / $_ODATA['admin_index_pagination']); // If the requested page is outside page limit if ($_SESSION['index_page'] != 1 && ($_SESSION['index_page'] > $_RDATA['index_pages'] || $_SESSION['index_page'] < 1)) { $_SESSION['index_page'] = max(1, min($_RDATA['index_pages'], (int)$_SESSION['index_page'])); // Redirect to a page within the limits header('Location: '.$_SERVER['REQUEST_URI'].'?ipage='.$_SESSION['index_page']); exit(); } } else $_SESSION['error'][] = 'Database did not return a search table row count.'; } else $_SESSION['error'][] = 'Database error reading search table row count: '.$err[2]; } else $_SESSION['error'][] = 'Database error reading search table: '.$err[2]; } else $_SESSION['message'][] = 'The search database is currently empty.'; break; case 'search': // Search Database Charsets $charsets = $_DDATA['pdo']->query( 'SELECT `content_charset`, COUNT(*) as `num` FROM `'.$_DDATA['tbprefix'].'crawldata` GROUP BY `content_charset` ORDER BY `num` DESC;' ); $err = $charsets->errorInfo(); if ($err[0] == '00000') { $charsets = $charsets->fetchAll(); foreach ($charsets as $row) { if (!$row['content_charset']) $row['content_charset'] = ''; $_RDATA['s_crawldata_info']['Charsets'][$row['content_charset']] = $row['num']; } } else $_SESSION['error'][] = 'Could not read charset counts from search database.'; // Search Database MIME-types $mimetypes = $_DDATA['pdo']->query( 'SELECT `content_mime`, COUNT(*) as `num` FROM `'.$_DDATA['tbprefix'].'crawldata` GROUP BY `content_mime` ORDER BY `num` DESC;' ); $err = $mimetypes->errorInfo(); if ($err[0] == '00000') { $mimetypes = $mimetypes->fetchAll(); foreach ($mimetypes as $row) { if (!$row['content_mime']) $row['content_mime'] = ''; $_RDATA['s_crawldata_info']['MIME-types'][$row['content_mime']] = $row['num']; } } else $_SESSION['error'][] = 'Could not read charset counts from search database.'; // Average hits per hour: First find the oldest `stamp` in the // database, then base all averages on the difference between that // time and now; also get average number of results $_RDATA['s_hours_since_oldest_hit'] = 0; $_RDATA['s_hits_per_hour'] = 0; $_RDATA['q_average_results'] = 0; $hits = $_DDATA['pdo']->query( 'SELECT MIN(`stamp`) AS `oldest`, COUNT(*) AS `hits`, AVG(`results`) AS `average` FROM `'.$_DDATA['tbprefix'].'query`;' ); $err = $hits->errorInfo(); if ($err[0] == '00000') { $hits = $hits->fetchAll(); if (count($hits) && !is_null($hits[0]['oldest']) && !is_null($hits[0]['hits'])) { $_RDATA['s_hours_since_oldest_hit'] = (time() - $hits[0]['oldest']) / 3600; $_RDATA['s_hits_per_hour'] = $hits[0]['hits'] / $_RDATA['s_hours_since_oldest_hit']; $_RDATA['q_average_results'] = $hits[0]['average']; } } else $_SESSION['error'][] = 'Could not read hit counts from query log.'; // Median number of results $_RDATA['q_median_results'] = 0; $median = $_DDATA['pdo']->query( 'SELECT `results` FROM `'.$_DDATA['tbprefix'].'query` ORDER BY `results`;' ); $err = $median->errorInfo(); if ($err[0] == '00000') { $median = $median->fetchAll(); if (count($median)) { $index = floor(count($median) / 2); if (count($median) & 1) { $_RDATA['q_median_results'] = $median[$index]['results']; } else { $_RDATA['q_median_results'] = ($median[$index - 1]['results'] + $median[$index]['results']) / 2; } } } else $_SESSION['error'][] = 'Could not read result counts from query log.'; break; case 'queries': $_RDATA['query_log_rows'] = array(); $queries = $_DDATA['pdo']->query( 'SELECT `t`.`query`, `t`.`results`, INET_NTOA(`t`.`ip`) AS `ipaddr`, REGEXP_REPLACE(`t`.`query`, \'^[[:punct:]]+\', \'\') AS `alpha`, `s`.`hits`, `s`.`ipuni`, `s`.`last_hit` FROM `'.$_DDATA['tbprefix'].'query` AS `t` INNER JOIN ( SELECT `query`, COUNT(DISTINCT(`ip`)) AS `ipuni`, COUNT(`query`) AS `hits`, MAX(`stamp`) AS `last_hit` FROM `'.$_DDATA['tbprefix'].'query` GROUP BY `query` ) AS `s` ON `s`.`query`=`t`.`query` AND `s`.`last_hit`=`t`.`stamp` GROUP BY `t`.`query` ORDER BY `alpha` ASC;' ); $err = $queries->errorInfo(); if ($err[0] == '00000') { $_RDATA['query_log_rows'] = $queries->fetchAll(); if (count($_RDATA['query_log_rows'])) { $x = 0; // Add the `alpha` sort order as an index foreach ($_RDATA['query_log_rows'] as $key => $query) $_RDATA['query_log_rows'][$key]['rownum'] = $x++; // On first load, sort list by # of hits usort($_RDATA['query_log_rows'], function($a, $b) { return $b['hits'] - $a['hits']; }); } else $_SESSION['message'][] = 'The query log is currently empty.'; } else $_SESSION['error'][] = 'Database error reading query log table: '.$err[2]; } } // Not logged in ?> Orcinus Site Search - <?php echo $_RDATA['admin_pages'][$_SESSION['admin_page']]; ?>

Orcinus Site Search

Crawler Management

Crawl Information

  • ago Currently crawling...

    Warning: The previous crawl did not complete successfully. Please check the crawl log for more details.

  • Crawler has not yet been run. Choose your settings and run your first crawl by using the button in the top menu bar.

Crawl Administration

  • Crawl Scheduling

    Automatic crawls are triggered by people visiting your search page. To allow crawls at any time, set these both to the same time.

  • Send Email on...

    >
    >

    Warning: PHPMailer could not be found or loaded. The application will not be able to send mail until it is installed correctly.

Sitemap Settings

  • Warning: Target sitemap file doesn't exist. Please create it.

    Warning: Target sitemap file is not writable. Please adjust permissions.

  • 1) { ?>

Crawl Settings

  • Options:
    • >
    • >
    • >
  • Timeouts & Delay

  • Maximum Limits

  • Link Filters

  • Categories

    Usually you'll want all your indexed pages in just one category. In some cases however, you may want to offer users an additional way to restrict results by putting groups of pages into multiple categories. You can set page categories from the Page Index.

  • Content Filters

Page Index

$_ODATA['admin_index_pagination']) { ?>
2) { ?> $row) { ?> 2) { ?>

Filters:

2) { ?>
URL Showing pages of Category Status Priority
Per page:
Updated
Unlisted

No pages to list.

Search Management

Search Information

    = 1) { ?>
  • = 24) { ?>
  • = 168) { ?>
  • No searches logged yet. To see search statistics here, start using your search engine. Tell your friends!

Query Log & Cache

  • The query log is a rolling log of searches on which the statistics above are based. Longer query log periods will give more accurate statistics, but also require more database space. (max: 255 days)

Offline Search Javascript

    1) { ?>

Search Settings

  • Query Limits

  • Match Weighting

    Additive Information
    Multipliers Information
  • Result Output

    The Output Encoding value should match the encoding of your search results page, and ideally match the character encoding of most of your crawled pages. UTF-8 is strongly recommended.

    Options:
    • >
    • >

Search Result Template

  • This template uses the Mustache templating system. See the Mustache manual for more information. To restore the default template, submit a blank textarea.

Query Log

country($query['ipaddr']); } catch(Exception $e) { $query['geo'] = false; } } ?>
Query Sort Hits Sort Results Sort Last Requested Sort
() raw['country']['iso_code'])) { if (file_exists(__DIR__.'/img/flags/'.strtolower($query['geo']->raw['country']['iso_code']).'.png')) { $flag = 'img/flags/'.strtolower($query['geo']->raw['country']['iso_code']).'.png'; $title = $query['geo']->raw['country']['names']['en']; $classname = 'svg-icon-flag'; } else { // Missing flag $flag = 'img/help.svg'; $title = $query['geo']->raw['country']['names']['en']; $classname = 'svg-icon'; } ?> <?php echo htmlspecialchars($title); ?>

Welcome

Log In