From f40be0ac64886d480c33cd63aa2483508f26606e Mon Sep 17 00:00:00 2001 From: Sascha Leib Date: Sun, 14 Sep 2025 19:32:48 +0200 Subject: [PATCH] Multiple updates --- .gitignore | 1 + config/default-config.json | 32 +++++------ config/known-bots.json | 6 ++ config/known-clients.json | 4 ++ config/known-platforms.json | 4 +- config/user-config.json | 21 ++++--- img/clients.png | Bin 19544 -> 20706 bytes img/links.png | Bin 0 -> 2299 bytes script.js | 107 +++++++++++++++++++++++++----------- style.less | 63 +++++++++++++++------ tick.php | 6 ++ 11 files changed, 170 insertions(+), 74 deletions(-) create mode 100644 img/links.png diff --git a/.gitignore b/.gitignore index d0f2f3e..cbf6a5e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ logs/*.log.txt logs/*.srv.txt logs/*.tck.txt +config/user-config.json php_errors.log diff --git a/config/default-config.json b/config/default-config.json index f220192..a3c1e72 100644 --- a/config/default-config.json +++ b/config/default-config.json @@ -23,11 +23,11 @@ }, {"func": "smallPageCount", "params": [1], "id": "onePage", "desc": "Visiter viewed only a single page", - "bot": 40 + "bot": 30 }, {"func": "noRecord", "params": ["log"], "id": "noClient", "desc": "No client-side JS log was recorded", - "bot": 50 + "bot": 40 }, {"func": "noRecord", "params": ["tck"], "id": "noTicks", "desc": "No client ticks were recorded", @@ -45,17 +45,13 @@ "id": "susClient", "desc": "Client identifier that is popular with bot networks", "bot": 10 }, - {"func": "combinationTest", "params": [["macos", "chrome"]], - "id": "unusualPC", "desc": "Unusual combination of platform and client", - "bot": 10 - }, - {"func": "combinationTest", "params": [["macos", "chromeold"],["macosold", "brave"],["winold", "edge"],["winold", "brave"]], + {"func": "combinationTest", "params": [["macos","chromeold"],["macos","msie"],["winold","edge"],["winold","brave"]], "id": "suspPC", "desc": "Suspicious combination of platform and client", "bot": 30 }, - {"func": "combinationTest", "params": [["macos", "msie"], ["win10", "safari"]], + {"func": "combinationTest", "params": [["macos","msie"],["win10","safari"],["macosold","brave"]], "id": "impPC", "desc": "Impossible combination of platform and client", - "bot": 80 + "bot": 70 }, {"func": "loadSpeed", "params": [3, 20], "id": "speedRun", "desc": "Average time between page loads is less than 20 seconds", @@ -65,31 +61,32 @@ "id": "noAcc", "desc": "No “Accept-Language” header", "bot": 40 }, + {"func": "clientAccepts", "params": ["zh"], + "id": "zhLang", "desc": "Client accepts Chinese language", + "bot": 60 + }, {"func": "matchesCountry", "params": ["BR", "CN", "RU", "US", "MX", "SG", "IN", "UY"], "id": "isFrom", "desc": "Location is in a known bot-spamming country.", "bot": 50 - }, - {"func": "matchesCountry", "params": ["ZZ"], - "id": "zzCtry", "desc": "Location could not be determined", - "bot": 20 } ], "ipRanges": [ - {"from": "3.0.0.0", "to": "3.255.255.254", "label": "Amazon Data Services [US]", "g": "US"}, + {"from": "3.0.0.0", "to": "3.255.255.254", "label": "Amazon Data Services [US]"}, {"from": "8.127.0.0", "to": "8.223.255.254", "label": "Alibaba [CN]"}, {"from": "24.240.0.0", "to": "24.247.255.255", "m": 13, "label": "Charter [US]"}, {"from": "27.106.0.0", "to": "27.106.127.254", "label": "Huawei [US]"}, {"from": "34.0.0.0", "to": "34.191.255.254", "label": "Google LLC"}, {"from": "45.0.0.0", "to": "45.255.255.254", "label": "Various small ISPs, mostly BR"}, {"from": "46.250.160.0", "to": "46.250.191.254", "label": "Huawei [MX]"}, + {"from": "47.200.0.0", "to": "47.203.255.255", "m": 14, "label": "Frontier Communications [US]"}, {"from": "49.0.200.0", "to": "49.0.255.254", "label": "Huawei [SG]"}, {"from": "66.249.64.0", "to": "66.249.95.255", "m": 19, "label": "Google LLC [US]"}, {"from": "84.37.35.0", "to": "84.37.255.254", "label": "GTT.net [US]"}, {"from": "94.74.64.0", "to": "94.74.127.254", "label": "Huawei [HK]"}, {"from": "101.0.0.0", "to": "101.255.255.254", "label": "ChinaNet [CN]"}, - {"from": "110.238.96.0", "to": "110.238.127.254", "label": "Huawei [SG]"}, + {"from": "110.238.80.0", "to": "110.238.127.254", "label": "Huawei [SG]"}, {"from": "111.119.192.0", "to": "111.119.255.254", "label": "Huawei [SG]"}, - {"from": "119.0.0.0", "to": "101.207.255.254", "label": "Unicom [CN]"}, + {"from": "119.0.0.0", "to": "119.207.255.254", "label": "Unicom [CN]"}, {"from": "121.91.168.", "to": "121.91.175.254", "label": "Huawei [HK]"}, {"from": "122.8.0.0", "to": "122.8.255.254", "label": "CN-ISP [CN]"}, {"from": "122.9.0.0", "to": "122.9.255.254", "label": "Huawei [CN]"}, @@ -109,8 +106,9 @@ {"from": "190.0.0.0", "to": "190.255.255.254", "label": "South-American ISPs (190.x)"}, {"from": "192.124.170.0", "to": "192.124.182.254", "label": "Relcom [CZ]"}, {"from": "195.37.0.0", "to": "195.37.255.255", "label": "DFN [DE]"}, - {"from": "2001:4800::::::", "to": "2001:4fff:ffff:ffff:ffff:ffff:ffff:ffff", "label": "Rackspace/Google [US]"}, + {"from": "2001:4860::::::", "to": "2001:4860:ffff:ffff:ffff:ffff:ffff:ffff", "m": 32, "label": "Google LLC [US]"}, {"from": "2001:0ee0::::::", "to": "2001:ee3:ffff:ffff:ffff:ffff:ffff:ffff", "m": 30, "label": "VNPT [VN]"}, + {"from": "2408:8210::::::", "to": "2408:8210:ffff:ffff:ffff:ffff:ffff:ffff", "m": 30, "label": "China Unicom [CN]"}, {"from": "2600:1f00::::::", "to": "2600:1fff:ffff:ffff:ffff:ffff:ffff:ffff", "m": "Amazon Cloud [US]"}, {"from": "2603:6010::::::", "to": "2603:6010:ffff:ffff:ffff:ffff:ffff:ffff", "m": 32, "label": "Charter [US]"}, {"from": "2603:8000::::::", "to": "2603:80ff:ffff:ffff:ffff:ffff:ffff:ffff", "m": 24, "label": "Charter [US]"}, diff --git a/config/known-bots.json b/config/known-bots.json index ededd49..646823c 100644 --- a/config/known-bots.json +++ b/config/known-bots.json @@ -22,6 +22,12 @@ "rx": ["APIs-Google"], "url": "https://developers.google.com/search/docs/crawling-indexing/google-special-case-crawlers" }, + {"id": "googleother", + "n": "GoogleOther", "geo": "US", + "r": ["GoogleOther"], + "rx": ["\\sGoogleOther(\\-\\w+)?[\\)\\/]"], + "url": "https://developers.google.com/search/docs/crawling-indexing/google-common-crawlers#googleother" + }, {"id": "applebot", "n": "Applebot", "geo": "US", "r": ["Applebot"], diff --git a/config/known-clients.json b/config/known-clients.json index d650d9f..f5bca20 100644 --- a/config/known-clients.json +++ b/config/known-clients.json @@ -23,6 +23,10 @@ "id": "huawei", "rx": [ "\\sHuaweiBrowser\\/(\\d+\\.\\d+)[\\s\\.]", "\\/harmony360Browser\\/(\\d+\\.\\d+)[\\s\\.]"] }, + {"n": "Ecosia Browser", + "id": "ecosia", + "rx": [ "\\(Ecosia ios@(\\d+)\\." ] + }, {"n": "Silk", "id": "silk", "rx": [ "\\Silk\\/(\\d+)\\." ] diff --git a/config/known-platforms.json b/config/known-platforms.json index a4a9ed5..817432e 100644 --- a/config/known-platforms.json +++ b/config/known-platforms.json @@ -25,11 +25,11 @@ }, {"n": "Android", "id": "android", - "rx": [ " Android[\\s;\\/](\\d\\d)\\.;\\s" ] + "rx": [ "Android[\\s;\\/](\\d\\d)[\\.;\\s]" ] }, {"n": "Old MacOS", "id": "macosold", - "rx": [ "\\sMac OS X 10[\\._](\\d|1[0-3])[\\._;\\s\\)]", "\\sMac OS X (1[123])[\\._]" ] + "rx": [ "\\sMac OS X 10[\\._](\\d|1[0-3])[\\._;\\s\\)]", "\\sMac OS X (1[123])[\\.;_\\s]" ] }, {"n": "MacOS", "id": "macos", diff --git a/config/user-config.json b/config/user-config.json index 739dc64..3f87f02 100644 --- a/config/user-config.json +++ b/config/user-config.json @@ -9,7 +9,7 @@ "id": "oldClient", "desc": "Obsolete browser version", "bot": 40 }, - {"func": "matchesPlatform", "params": ["winold", "macosold"], + {"func": "matchesPlatform", "params": ["winold", "macosold", "androidold"], "id": "oldOS", "desc": "Obsolete platform version", "bot": 40 }, @@ -17,6 +17,10 @@ "id": "serverOS", "desc": "Server OS", "bot": 40 }, + {"func": "matchesPlatform", "params": ["null"], + "id": "noOS", "desc": "Unknown or missing OS information", + "bot": 40 + }, {"func": "smallPageCount", "params": [1], "id": "onePage", "desc": "Visiter viewed only a single page", "bot": 40 @@ -77,12 +81,13 @@ "ipRanges": [ {"from": "3.0.0.0", "to": "3.255.255.254", "label": "Amazon Data Services [US]"}, {"from": "8.127.0.0", "to": "8.223.255.254", "label": "Alibaba [CN]"}, - {"from": "24.240.0.0", "to": "24.243.255.254", "label": "Charter [US]"}, + {"from": "24.240.0.0", "to": "24.247.255.255", "m": 13, "label": "Charter [US]"}, {"from": "27.106.0.0", "to": "27.106.127.254", "label": "Huawei [US]"}, {"from": "34.0.0.0", "to": "34.191.255.254", "label": "Google LLC"}, {"from": "45.0.0.0", "to": "45.255.255.254", "label": "Various small ISPs, mostly BR"}, {"from": "46.250.160.0", "to": "46.250.191.254", "label": "Huawei [MX]"}, {"from": "49.0.200.0", "to": "49.0.255.254", "label": "Huawei [SG]"}, + {"from": "66.249.64.0", "to": "66.249.95.255", "m": 19, "label": "Google LLC [US]"}, {"from": "84.37.35.0", "to": "84.37.255.254", "label": "GTT.net [US]"}, {"from": "94.74.64.0", "to": "94.74.127.254", "label": "Huawei [HK]"}, {"from": "101.0.0.0", "to": "101.255.255.254", "label": "ChinaNet [CN]"}, @@ -106,12 +111,14 @@ {"from": "188.0.0.0", "to": "188.255.255.254", "label": "South-American ISPs (188.x)"}, {"from": "189.0.0.0", "to": "189.255.255.254", "label": "South-American ISPs (189.x)"}, {"from": "190.0.0.0", "to": "190.255.255.254", "label": "South-American ISPs (190.x)"}, - {"from": "192.124.170.0", "to": "192.124.182.254", "label": "Relcom [CZ]"}, + {"from": "192.124.170.0", "to": "192.124.182.254", "label": "Relcom [CZ]"}, {"from": "195.37.0.0", "to": "195.37.255.255", "label": "DFN [DE]"}, - {"from": "2001:4800::::::", "to": "2001:4fff:ffff:ffff:ffff:ffff:ffff:ffff", "label": "Rackspace/Google [US]"}, - {"from": "2001:0ee0::::::", "to": "2001:ee3:ffff:ffff:ffff:ffff:ffff:ffff", "mask": 30, "label": "VNPT [VN]"}, - {"from": "2600:1f00::::::", "to": "2600:1fff:ffff:ffff:ffff:ffff:ffff:ffff", "label": "Amazon Cloud [US]"}, - {"from": "2804:::::::", "to": "2804:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", "label": "Inspire [BR]"}, + {"from": "2001:4860::::::", "to": "2001:4860:ffff:ffff:ffff:ffff:ffff:ffff", "m": 32, "label": "Google LLC [US]"}, + {"from": "2001:0ee0::::::", "to": "2001:ee3:ffff:ffff:ffff:ffff:ffff:ffff", "m": 30, "label": "VNPT [VN]"}, + {"from": "2600:1f00::::::", "to": "2600:1fff:ffff:ffff:ffff:ffff:ffff:ffff", "m": "Amazon Cloud [US]"}, + {"from": "2603:6010::::::", "to": "2603:6010:ffff:ffff:ffff:ffff:ffff:ffff", "m": 32, "label": "Charter [US]"}, + {"from": "2603:8000::::::", "to": "2603:80ff:ffff:ffff:ffff:ffff:ffff:ffff", "m": 24, "label": "Charter [US]"}, + {"from": "2804:::::::", "to": "2804:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", "m": 16, "label": "Inspire [BR]"}, {"from": "2a0a:4cc0::::::", "to": "2a0a:4cc0:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", "label": "Netcup [DE]"} ] } \ No newline at end of file diff --git a/img/clients.png b/img/clients.png index fd9d06bba32f300d41da7c5218228db878ccf44d..b087ff6eeec789e500771e1fad1b4935c57a20b5 100644 GIT binary patch delta 20611 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 Hu0mjf#xkN= diff --git a/img/links.png b/img/links.png new file mode 100644 index 0000000000000000000000000000000000000000..7fd986976a4773454046605a468c987634eed49c GIT binary patch literal 2299 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 literal 0 HcmV?d00001 diff --git a/script.js b/script.js index 1062364..b6e1592 100644 --- a/script.js +++ b/script.js @@ -107,7 +107,7 @@ const BotMon = { _formatTime: function(date) { if (date) { - return ('0'+date.getHours()).slice(-2) + ':' + ('0'+date.getMinutes()).slice(-2) + ':' + ('0'+date.getSeconds()).slice(-2); + return date.getHours() + ':' + ('0'+date.getMinutes()).slice(-2) + ':' + ('0'+date.getSeconds()).slice(-2); } else { return null; } @@ -433,7 +433,7 @@ BotMon.live = { // get the page view info: let pv = model._getPageView(visitor, dat); if (!pv) { - console.warn(`No page view for visit ID “${dat.id}”, page “${dat.pg}”, registering a new one.`); + console.info(`No page view for visit ID “${dat.id}”, page “${dat.pg}”, registering a new one.`); pv = model._makePageView(dat, type); visitor._pageViews.push(pv); } @@ -448,19 +448,21 @@ BotMon.live = { // helper function to create a new "page view" item: _makePageView: function(data, type) { + // console.info('_makePageView', data); // try to parse the referrer: let rUrl = null; try { rUrl = ( data.ref && data.ref !== '' ? new URL(data.ref) : null ); } catch (e) { - console.info(`Invalid referer: “${data.ref}”.`); + console.warn(`Invalid referer: “${data.ref}”.`); } return { _by: type, ip: data.ip, pg: data.pg, + lang: data.lang || '??', _ref: rUrl, _firstSeen: data.ts, _lastSeen: data.ts, @@ -1293,6 +1295,16 @@ BotMon.live = { return false; }, + // the "Accept language" header contains certain entries: + clientAccepts: function(visitor, ...languages) { + //console.info('clientAccepts', visitor.accept, languages); + + if (visitor.accept && languages) {; + return ( visitor.accept.split(',').filter(lang => languages.includes(lang)).length > 0 ); + } + return false; + }, + // Is there an accept-language field defined at all? noAcceptLang: function(visitor) { @@ -1886,7 +1898,21 @@ BotMon.live = { platformName + ( data._platform.v > 0 ? ' (' + data._platform.v + ')' : '' ) )); dl.appendChild(make('dt', {}, "IP-Address:")); - dl.appendChild(make('dd', {'class': 'has_icon ipaddr ip' + ipType}, data.ip)); + const ipItem = make('dd', {'class': 'has_icon ipaddr ip' + ipType}); + ipItem.appendChild(make('span', {'class': 'address'} , data.ip)); + ipItem.appendChild(make('a', { + 'class': 'icon_only extlink dnscheck', + 'href': `https://dnschecker.org/ip-location.php?ip=${encodeURIComponent(data.ip)}`, + 'target': 'dnscheck', + 'title': "View this address on DNSChecker.org" + } , "Check Address")); + ipItem.appendChild(make('a', { + 'class': 'icon_only extlink ipinfo', + 'href': `https://ipinfo.io/${encodeURIComponent(data.ip)}`, + 'target': 'ipinfo', + 'title': "View this address on IPInfo.io" + } , "DNS Info")); + dl.appendChild(ipItem); /*dl.appendChild(make('dt', {}, "ID:")); dl.appendChild(make('dd', {'class': 'has_icon ip' + data.typ}, data.id));*/ @@ -1906,7 +1932,7 @@ BotMon.live = { dl.appendChild(make('dd', {'class': 'agent'}, data.agent)); dl.appendChild(make('dt', {}, "Languages:")); - dl.appendChild(make('dd', {'class': 'langs'}, "Client accepts: [" + data.accept + "]; Page: [" + data.lang + ']')); + dl.appendChild(make('dd', {'class': 'langs'}, ` [${data.accept}]`)); if (data.geo && data.geo !=='') { dl.appendChild(make('dt', {}, "Location:")); @@ -1931,37 +1957,56 @@ BotMon.live = { const pageList = make('ul'); /* list all page views */ + data._pageViews.sort( (a, b) => a._firstSeen - b._firstSeen ); data._pageViews.forEach( (page) => { + //console.log("page:",page); + const pgLi = make('li'); - let visitTimeStr = "Bounce"; - const visitDuration = page._lastSeen.getTime() - page._firstSeen.getTime(); - if (visitDuration > 0) { - visitTimeStr = Math.floor(visitDuration / 1000) + "s"; - } + const lGroup = make('span'); // left group: - pgLi.appendChild(make('span', {}, page.pg)); /* DW Page ID */ - if (page._ref) { - pgLi.appendChild(make('span', { - 'data-ref': page._ref.host, - 'title': "Referrer: " + page._ref.full - }, page._ref.site)); - } else { - pgLi.appendChild(make('span', { - }, "No referer")); - } - pgLi.appendChild(make('span', {}, ( page._seenBy ? page._seenBy.join(', ') : '—') + '; ' + page._tickCount)); - pgLi.appendChild(make('span', {}, BotMon.t._formatTime(page._firstSeen))); + lGroup.appendChild(make('span', { + 'data-lang': page.lang, + 'title': "PageID: " + page.pg + }, page.pg)); /* DW Page ID */ + + pgLi.appendChild(lGroup); // end of left group + + const rGroup = make('span'); // right group: + + let visitTimeStr = "Bounce"; + const visitDuration = page._lastSeen.getTime() - page._firstSeen.getTime(); + if (visitDuration > 0) { + visitTimeStr = Math.floor(visitDuration / 1000) + "s"; + } + + /*if (page._ref) { + rGroup.appendChild(make('span', { + 'data-ref': page._ref.host, + 'title': "Referrer: " + page._ref.full + }, page._ref.site)); + } else { + rGroup.appendChild(make('span', { + }, "No referer")); + }*/ + //rGroup.appendChild(make('span', {}, ( page._seenBy ? page._seenBy.join(', ') : '—') + '; ' + page._tickCount)); + + // get the time difference: + const tDiff = BotMon.t._formatTimeDiff(page._firstSeen, page._lastSeen); + if (tDiff) { + rGroup.appendChild(make('span', {'class': 'visit-length', 'title': 'Last seen: ' + page._lastSeen.toLocaleString()}, tDiff)); + } else { + rGroup.appendChild(make('span', { + 'class': 'bounce', + 'title': "Visitor bounced"}, "Bounce")); + } + rGroup.appendChild(make('span', { + 'class': 'first-seen', + 'title': "First visited: " + page._firstSeen.toLocaleString() + }, BotMon.t._formatTime(page._firstSeen))); + + pgLi.appendChild(rGroup); // end of right group - // get the time difference: - const tDiff = BotMon.t._formatTimeDiff(page._firstSeen, page._lastSeen); - if (tDiff) { - pgLi.appendChild(make('span', {'class': 'visit-length', 'title': 'Last seen: ' + page._lastSeen.toLocaleString()}, tDiff)); - } else { - pgLi.appendChild(make('span', { - 'class': 'bounce', - 'title': "Visitor bounced"}, "Bounce")); - } pageList.appendChild(pgLi); }); diff --git a/style.less b/style.less index 4108677..4f5fede 100644 --- a/style.less +++ b/style.less @@ -40,7 +40,7 @@ /* Bot icons */ &.bot::before { background-image: url('img/bots.png') } - &.bot_googlebot::before, &.bot_googleads::before, &.bot_googleapi::before { background-position-y: -20px } + &.bot_googlebot::before, &.bot_googleads::before, &.bot_googleapi::before, &.bot_googleother::before { background-position-y: -20px } &.bot_bingbot::before { background-position-y: -40px } &.bot_applebot::before { background-position-y: -60px } &.bot_openai::before { background-position-y: -80px } @@ -84,6 +84,7 @@ &.cl_silk::before { background-position-y: -280px } &.cl_ffold::before { background-position-y: -300px } &.cl_chromeold::before { background-position-y: -320px } + &.cl_ecosia::before { background-position-y: -340px } /* Country flags */ /* Note: flag images and CSS adapted from: https://github.com/lafeber/world-flags-sprite/ */ @@ -332,6 +333,11 @@ &.typ_php::before { background-position-y: -40px } &.typ_ip::before { background-position-y: -60px } &.typ_usr::before { background-position-y: -80px } + + /* External link icons */ + &.extlink::before { background-image: url('img/links.png') } + &.extlink.dnscheck::before { background-position-y: -20px } + &.extlink.ipinfo::before { background-position-y: -40px } } /* grid layout for the overview: */ @@ -524,26 +530,49 @@ & { display: flex; justify-content: space-between; - align-items: center; + align-items: baseline; + white-space: nowrap; + line-height: 1.2rem; + margin: 0; + padding: 0 .25em; + } + &:nth-child(odd) { + background-color: #DFDFDF; } span { - &.visit-length { - min-width: min-content; - } - &.bounce { - width: 1.25em; height: 1.25em; - overflow: hidden; - } - &.bounce::before { - display: inline-block; - content: ''; - width: 1.25em; height: 1.25em; - background: transparent url('img/bounce.svg') center no-repeat; - background-size: 1.25em; - } + display: inline-block; } } } + span[data-lang] { + overflow: hidden; + text-overflow: ellipsis; + } + span[data-lang]::after { + content: attr(data-lang); + font-size: smaller; + color: #555; + border: #555 solid 1px; + line-height: 1.25; + border-radius: 2pt; + padding: 0 1pt; + margin-left: .2em; + } + span.first-seen { + min-width: 4.2em; + text-align: right;; + } + span.bounce { + width: 1.25em; height: 1.25em; + overflow: hidden; + } + span.bounce::before { + display: inline-block; + content: ''; + width: 1.25em; height: 1.25em; + background: transparent url('img/bounce.svg') center no-repeat; + background-size: 1.25em; + } } } @@ -554,7 +583,7 @@ align-items: center; } li:nth-child(odd) { - background-color: #EEE; + background-color: #DFDFDF; } li.total { border-top: #333 solid 1px; diff --git a/tick.php b/tick.php index 1d46b1e..67b4550 100644 --- a/tick.php +++ b/tick.php @@ -2,6 +2,12 @@ // Note: this script is normally called in HEAD mode, therefore it can not return any payload. + // quit out if it is called without athe right parameters: + if (!isset($_GET['id']) || !isset($_GET['p'])) { + http_response_code(400); + die("Parameter error."); + } + // what is the session identifier? $sessionId = preg_replace('/[\x00-\x1F{};\"\']/', "\u{FFFD}", $_GET['id']) /* clean json parameter */ ?? session_id()