From f4417fde3b994fe0c6f5285c818940fa0214754b Mon Sep 17 00:00:00 2001 From: Sascha Leib Date: Thu, 4 Sep 2025 23:01:46 +0200 Subject: [PATCH] Several smaller improvements --- .gitignore | 3 - data/known-bots.json | 6 +- data/known-clients.json | 14 ++- data/known-platforms.json | 8 +- img/ahrefs.png | Bin 0 -> 806 bytes img/anthropic.png | Bin 0 -> 860 bytes img/babbar.png | Bin 0 -> 1446 bytes img/bounce.svg | 56 +++++++++ img/bytedance.svg | 65 ++++++++++ img/ccbot.svg | 70 +++++++++++ img/dataforseo.png | Bin 0 -> 1198 bytes img/freebsd.png | Bin 0 -> 2026 bytes img/hive.svg | 105 ++++++++++++++++ img/hunter.png | Bin 0 -> 952 bytes img/majestic.png | Bin 0 -> 1914 bytes img/netestate.png | Bin 0 -> 1783 bytes img/page.svg | 1 + img/perplexity.svg | 49 ++++++++ img/petal.svg | 110 ++++++++++++++++ img/semrush.png | Bin 0 -> 745 bytes img/serpstat.svg | 56 +++++++++ img/vivaldi.svg | 59 +++++++++ php_errors.log | 8 ++ script.js | 257 ++++++++++++++++++++++---------------- style.less | 42 ++++++- 25 files changed, 782 insertions(+), 127 deletions(-) create mode 100644 img/ahrefs.png create mode 100644 img/anthropic.png create mode 100644 img/babbar.png create mode 100644 img/bounce.svg create mode 100644 img/bytedance.svg create mode 100644 img/ccbot.svg create mode 100644 img/dataforseo.png create mode 100644 img/freebsd.png create mode 100644 img/hive.svg create mode 100644 img/hunter.png create mode 100644 img/majestic.png create mode 100644 img/netestate.png create mode 100644 img/page.svg create mode 100644 img/perplexity.svg create mode 100644 img/petal.svg create mode 100644 img/semrush.png create mode 100644 img/serpstat.svg create mode 100644 img/vivaldi.svg create mode 100644 php_errors.log diff --git a/.gitignore b/.gitignore index f17cee9..9e5648a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,4 @@ .DS_Store -*.log -*.srv -*.tck logs/*.log.txt logs/*.srv.txt logs/*.tck.txt diff --git a/data/known-bots.json b/data/known-bots.json index 50f2b81..e3d9ec0 100644 --- a/data/known-bots.json +++ b/data/known-bots.json @@ -29,14 +29,14 @@ "rx": ["Applebot\\/(\\d+\\.\\d+);"], "url": "http://www.apple.com/go/applebot" }, - {"id": "openaibots", - "n": "OpenAI/ChatGPT Bots", + {"id": "openai", + "n": "OpenAI/ChatGPT", "r": ["OAI-SearchBot", "ChatGPT-User", "GPTBot"], "rx": ["OAI-SearchBot\\/(\\d+\\.\\d+);", "ChatGPT-User\\/(\\d+\\.\\d+);", "GPTBot\\/(\\d+\\.\\d+);"], "url": "https://platform.openai.com/docs/bots/" }, {"id": "metabots", - "n": "Meta Web Crawlers", + "n": "Meta/Facebook", "r": ["facebookexternalhit", "facebookcatalog","meta-webindexer","meta-externalads","meta-externalagent","meta-externalfetcher"], "rx": ["facebook\\w+\\/(\\d+\\.\\d+)", "meta-\\w+\\/(\\d+\\.\\d+)"], "url": "https://developers.facebook.com/docs/sharing/webmasters/crawler" diff --git a/data/known-clients.json b/data/known-clients.json index aa93358..dbabeee 100644 --- a/data/known-clients.json +++ b/data/known-clients.json @@ -15,6 +15,14 @@ "id": "huawei", "rx": [ "\\sHuaweiBrowser\\/(\\d+\\.\\d+)[\\s\\.]", "\\/harmony360Browser\\/(\\d+\\.\\d+)[\\s\\.]"] }, + {"n": "DuckDuckGo", + "id": "ddg", + "rx": [ "\\sDdg\\/(\\S+)" ] + }, + {"n": "Vivaldi", + "id": "vivaldi", + "rx": [ "\\sVivaldi\\/(\\d+\\.\\d+)[\\s\\.]" ] + }, {"n": "Internet Explorer", "id": "msie", "rx": [ "\\sMSIE\\s(\\d+\\.\\d+b?);" ], @@ -34,16 +42,12 @@ }, {"n": "Chrome", "id": "chrome", - "rx": [ "\\sChrome\\/(1\\d\\d\\.\\d+)[\\.\\s;]" ] + "rx": [ "\\sChrome\\/(1\\d\\d)\\.\\d+" ] }, {"n": "Safari", "id": "safari", "rx": [ "\\sSafari\\/(\\S+)" ] }, - {"n": "DuckDuckGo", - "id": "ddg", - "rx": [ "\\sDdg\\/(\\S+)" ] - }, {"n": "Firefox", "id": "firefox", "rx": [ "\\sFirefox\\/(\\S+)" ] diff --git a/data/known-platforms.json b/data/known-platforms.json index 3148353..51c4f60 100644 --- a/data/known-platforms.json +++ b/data/known-platforms.json @@ -1,15 +1,19 @@ [ {"n": "Win10/11", "id": "win10", - "rx": [ "\\(Windows NT (1\\d\\.\\d);" ] + "rx": [ "[\\(\\s]Windows\\sNT\\s(1\\d\\.\\d)[\\)\\s\\.;]" ] }, {"n": "Linux", "id": "linux", "rx": [ "\\sLinux\\s" ] }, + {"n": "BSD", + "id": "bsd", + "rx": [ "\\sNetBSD[\\);\\s]", "\\sOpenBSD[\\);\\s]", "\\sFreeBSD[\\);\\s]" ] + }, {"n": "iOS/iPadOS", "id": "ios", - "rx": [ "\\sFxiOS\\/(\\d+\\.\\d+)\\s", "\\sCriOS\\/(\\d+\\.\\d+)\\." ] + "rx": [ "\\sFxiOS\\/(\\d+\\.\\d+)\\s", "\\siPhone\\sOS\\s([\\d\\._]+)\\s", "\\siPadOS\\s([\\d\\._]+)\\s", "\\sCriOS\\/(\\d+\\.\\d+)\\." ] }, {"n": "Android", "id": "android", diff --git a/img/ahrefs.png b/img/ahrefs.png new file mode 100644 index 0000000000000000000000000000000000000000..1802d9ff6d4e74118f4e57df5d0aa57a61185d37 GIT binary patch literal 806 zcmV+>1KIqEP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0=r2>K~y+TwNy<^ z6G0Sy^Rr90w1vuAL81H@i6J&5UeJRH9F>#tV)TN72PFotUOX5tgaaH%42fPuFPdmV zq9;9=c<^E(5+V^btx710(3TR~?(U4Q-C}o3Ax81bYj%F#d^7KxZ%UL?A7D2?i{F37 z|0FVGrNHq*$YNGG%83O2vJy77ghfD53=@FZscyK$HY|wLlF1wO!2lD^t)+x#_epF{ zFh2b8%tTUGXnsd0+$R#?QAk^}7H-s9nj8`Kw&-)szR}jeNRVehlC3qmiSW=^gtb+N zLTM&Q6AVF+2&1eDTxCs7nTo>f0^GDl+i--}(rDRt- z?;r9-4r?J@@l`Xeim5756fG!9*Cz>(tIHgFJeGP7W&*DY+SD!o3q|It{>wf+V)x;?)$ zN<<2W*_e3xV%6?)Ml?@;7LER9W-XDjH6lO_T!fcM@je_+fU!eYi%q;KjXZgksj+gk zerj50iIpmN9W(q4U6Kct9wPHX6j1p;8|l!yxJ=pfp`(Z*${gwt+X0Rgw8VnI kW?7V>GSOdPmxus<0YF6&9(rn51ONa407*qoM6N<$g1&fRG5`Po literal 0 HcmV?d00001 diff --git a/img/anthropic.png b/img/anthropic.png new file mode 100644 index 0000000000000000000000000000000000000000..18ea8a0a7e1712982c37d711384dbefd17f8e5ad GIT binary patch literal 860 zcmV-i1Ec(jP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf6951U69E94oEQKA0`W;iK~zXft(MPA z({UKbpXFufL7_!O&BQ}>@}QmCk}(w%4FVB#7a>Y1cE}$IGMM+QPEz2(x%Cfp*&NA6 z=!B^!JxGf4SBI$9QuJWd_UZjR-|r^-;jHupZ$6*T^Sqzu^WFFR`F@#!ilCIbiQztE zgRVnni1`GqK_8%Z27}=v2mcy0u7-TjA#@V#c?(tR<;8)q6G}k;3fFY%Z3+W}Q>>@M zskh4piFPf2Cba8qH4wN0eUa4Jz`d?=Z#hL+yvFdD=edMJAzE5mBBRkr4u^v(Dk>-# z4AS!Q64lk+qK1YB-I>Q5oUSL_+zjnPdF<`&DXZ0@U=~eJPfI)!iOAYwv54mwIAP`u zdSqFExw*MabC%QTRLNvg9UL5}du?qJr_@&Mx9;Si3|h+;ynf%Cl`6ET(-8hGFQG4TT`!Ij>>#|d|dL|+uNBudyip}e?d8v zMN=jq1_E2dcmSsmN-%E%Cm- zK9x$Pq-k?=v&6Wj0Q0p(^oY5)w^z=5F6sM@2d@$d z?V~#|Fd#9H$0KWBt_WZJhTa&75rkDqPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1v^PZK~y+TZB=Pd zQ&$xJl0cBiY9h9{AX^56wnV95-IxmE!cb|gGY->^woaGnHq%90rc-CEwU$xaL2wv% zR0>uQY()hkP}5*o6j@X-1c-(}0wDnsASC4W-T-dx_v5`Y=brn$^UnRwxg0_W{)3Sb zYinCin0StnxNon9jUapmB0TZ32#aPz=sp$pG`LgmXOVMOzGU%vi^b|7Fi&76P%(s0 zRahm5M2b_*FpN$`KE^XdT_#khnPE0t0awa0-xHPVP?U&U>(Q|mMN1IvhWA>KT!~vf z&OOt3LexHhz`vn1F`LWf&?kq(86UT|+*UQzC^agL2$oG^>?*8OZ++PKWJJ!@c$%_%$2{IZX zA4Z7;%jQn{8Hj^;c?n9(HdR(_&Og6q`O;aRe^wjt>bZ)_yJ14)F9TfgNyBu#=&4md zBFG~@*HDvKtv32RaOf&j?V`6Nu|xyQ>tPck2kVauHAuL72t+< z7GcCZT2Xo5$q&rtm@U?S^Z%&l0jWV$b!gIqt26>Otngc>sL-qox>B`ll+p_n|OSU&Pr@pmC zl(ey|x#gim61ekQaoWKLhW^1wKlV2bec-BxSj_^wF=(8^xw5=? zu`xlzc5J9Zm=ujVh=b>(zB@-zr=#NXf6<4A4GdUZfPfh&9-Gz??KdX_XWTYHUp_vp zop@X>kAnrS>`Q!F4<}d@J8P%y+%pNT(2WWSmT`D`xQ9gvR2>7<8x%O3{#t#5TEN4Z zIA{|QE`m~}&po4C7V`q1@1p6ZVH}aj!v=JYVXFY#g?+Zgk7T7~O;i+KWVEqKo%X{un#!9g68a_S_4eRM?|}It!w4>$5kr6U;UGZ)*{fip zlFM6xJx8*yQ@f_N9im@>9|I#YqF>7bege|3Ub{n=ZYmxCd$W#6sm(O`JGr4Iusg_C zHwX#|Wpvo>-|Q-&d#;r-wQ4km(>XW3-g)7RFVANmtx&0YsZ-hB6SXumV)5bLUL$RS zR4EDhlMIX!)*|&)CN+t!*O-)YoHoIUlT}8eg}J6dyXSgEOGsn}O|7o3oq8@S zSvt9Q*(#fm^aS?TBCP|(i}8jSx?a=%1LeORYz>d{-If|08X|IW;c2y|GHKVv3*B)E zeuvT%B~c6S^&>)tBmr{c;N^y?Q9Ce-9WoS|@RtNhp_s7QW%9Pd;+D+JZcL0h<-vb@ zt7vmd_}chLA777_J|rv9X~(^l>_8b + + + + arrow-down-left + + + + arrow-down-left + + + + + + diff --git a/img/bytedance.svg b/img/bytedance.svg new file mode 100644 index 0000000..7b7cef5 --- /dev/null +++ b/img/bytedance.svg @@ -0,0 +1,65 @@ + + + + + + + + + + + + diff --git a/img/ccbot.svg b/img/ccbot.svg new file mode 100644 index 0000000..3bf9da5 --- /dev/null +++ b/img/ccbot.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + diff --git a/img/dataforseo.png b/img/dataforseo.png new file mode 100644 index 0000000000000000000000000000000000000000..c4da2c37a450078d81ecad51c7208153b2ee9367 GIT binary patch literal 1198 zcmV;f1X25mP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1Vc$gK~zXfl~#Rd zl~ox3J@32S*(RkFML|Q$z>hn(U5B$}vkxc~1RG*tP%!5zX#_QhvV=&8B!U)w*xKli zzWhkn7iCnWrJGaS=5FdAnYSQ6NK@?Yw)^qk)9*R&d#~^2#Qcrl&hv53^PJ~7=e(N$ zP+B-8w?d>8UiOGleOgsl9o-EAB;Fvuj;uK+1#eu_yps-o3oQhOjy$#h{!g`KbGuvTSOV26tk-u*-ntV;|x zYxQv4N)fkows_e?hW&2i;to4WF*X5vY<}W+EJ$z*Cp2=bw%SE7t*oRoQnApF67;;6 zeZ0^X-!;t1&!kf)zddnut@gTzn`d>nu3Nz~l2@qC@~uTAxo$p_9QG4bb$`xbsmdXI zX^gk>_xS360)0YobJuX##Ma#JTZ-6{7+$qPrbWBw(b-Q!__iEi@J0q7QHAZB%bh+( zF~*%~llGHuGr%G1kG^*`E8a~ps(OGd+Zl5h`~fOsuc9$ehk~zU@VyitC+o=t==hbY|?C%Uo~kWcSpD!G$WH>x(wSxLwvk7)VaMA^gP**Qvo~Hh8Y21~04b9mGcJ zttwv%T+`uJ<4KisLwJ$HI+X+b;p7c|(Tk^~tm9pQ6Kv00)YAq31RTlbVZS{J>Wjwt z4?C>G|LheYxH~g|S`{NT7~;GZifPryA;kdAWwo$xfotyIU|UrH*Y0#UX&dG6XP}g2 zZwO>f@&V`Q{nwr9gH&o|^^sa^rfk74i?)eJT!dEsnU%7G_>?r`_>Og622J^r!F)vV+-ij!6UpU@;r znB+8N+pfwR_y|q~Ur`3f!%KY!OY6+%F`wcVGOM=BAVVg&sWM;np}`fl0#bJ`RWta% z3Hix4K{bPj(z%S{B622qquPl-N&VkuC$C~p;Vr!JETqkT0}25C1Nkc3J`W1#F#rGn M07*qoM6N<$f_tGmUH||9 literal 0 HcmV?d00001 diff --git a/img/freebsd.png b/img/freebsd.png new file mode 100644 index 0000000000000000000000000000000000000000..6305f5805882ed164dfcaf6656bcdb86a499e248 GIT binary patch literal 2026 zcmZ8idpy&7AOCG*tu*A}V3Z6yNE$PjLo(aka#_xjG)E$vTUKt7Yn`wi*F(BUuF1%f zYZ1-a6H0Qa9<9u6OD-{8n7d~>=lSRPyk76``~CTR-rvvX``?#AaM6~aPvjE9A@LYtUE0Me(YiML>t`;~`De*L&^>hqybkql6l0+In zfTRJCL^(;I_K)6vjV=iCqYja1BM=ynm#~)vfvHkI>Om5{9c8%yFeNelkNNv@r$^D*k)w_D1RAzbEBM^mc$HbHP8H?iS_}_0KIMGLmjYl1Fylw7sz5sOD?}+az&|9jrU%EnuHFfbgt0aKbx}(Z}(Xj^+jJw zWb@;n4whMt@U-#4pcIJRNC`u3FcV8P`%OyptI!_Rh>89P(C8xPEEpRQ2Mc zQ|*tp_UG4lNgp(gIA>zLI^nt2#K^}EdUis){?5qHfH(wmobfz553Qv@3F&Nuy%(+YBZ$g#}5WXQJ=@ZOr z#0NuKfR#=FBom)!b-NUfv5+}XXg4u<_R+?!ssfL9rM_S0uM&l9*Rgdqd-}XUK(C(p z`AJ;}&quSzfl}BRA~y1z+e_!SK#dQq&3O*$bE%;w5ynloqZFBz&w7=K3Cm11!NC9F7=6an@?Lha2uZt6Lp zRD-=d$CS#68qNu_DIC8LI;=(`N;7;3oWeNpFcv#Myn4{!5ud6W?Kq|ueCp0*hWfol zu}xd(LG#1#OSN*t3$XI<29J1wiqr{D=jj_4th$A8e{Vw}7-ZmaqAYl&7v|jS8ygGl z6_5OJ-&;yq_6YtBe^^c|da(BPRiW}9cnH?@j6#V^q5PSR+P>RRvwf*_){a-aJ&Lq! z6peVxrU`$*Z{QObix9;i6jQ4nAaO1ewI2t5{;v1>+<0^duTGX1(mU~7K)RkXUd6I6 z5gqXC8cE)myrjDsDrK638B|Z6vw_Bv!8EtDwzh0G1&6xMT_Gb_&-D-=e{VJ|J||Ri zWKITDbSy@55eUL$&5&=xD(Yo;eQ`clTNavMbF7`JD?b&v(>blE;EJuYVYg2GvX zL1BBCLX(Bdy1!Ulan^$R1*u2KOk4L4C)V(xOOXsNH%I*cz;LhF53WyC=lG{4C82@`kUNbewRz zS^ZO~I=f4IEiJ8{9G=fc?Zu()b~+pYE9C$T}`xN$$g=& zu3gHbFW-7QkonwvPrrVll!`&s5bQUzM@Wt_b#8emNM(v_(AGNJRpZHvu{3^iWE7Ka z)hpsP2EWfQ7v${Fuw`2J%fvA#es4*0ve?J+Ew0^O<4AOg)7p*c&#KkB3dczHGK=H# zXTuU#>f5p?0aPP)dd3F(JifKY%&rzq)#6s|_jk~?Z%@NUT*UrsC*vc3YuNugB3XyS zJVhW_f-8f&|I%f5HnR4|8fwd7<_CSdO7As`uPv{%Q+Mp+XT)BEz?CTk6e$+z?Q%1q zaGsy1P)#VmQz@ipQ?5puN4Yc zQ|skpK*#m7bjB4azOq*l zMK|g8uJP8b6ANxWR_nN!>8H=Olq&yS!Oy~my`=43Y-xYd6^?60e!IYN3am4YeJ^xt jTbf~Xe7(1&m6Ql9G)z^@s0lZ=KP*S0D}il$`tpAPbJ>J} literal 0 HcmV?d00001 diff --git a/img/hive.svg b/img/hive.svg new file mode 100644 index 0000000..98c9c18 --- /dev/null +++ b/img/hive.svg @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/img/hunter.png b/img/hunter.png new file mode 100644 index 0000000000000000000000000000000000000000..4180226f5fd3895aa3bc4494c7ca4614cdb7e02a GIT binary patch literal 952 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 X&v{ep&eiOXEI+_-aRgi$vL^E%DC+ht literal 0 HcmV?d00001 diff --git a/img/netestate.png b/img/netestate.png new file mode 100644 index 0000000000000000000000000000000000000000..8bcabaa0c04f294a72b4098bd9ec09b48073ac95 GIT binary patch literal 1783 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qt-49wP6v-9O7C~?S5nAKu~iB;^)>J+ zYH@N=W&S0onb8|oQ=yarR~>x*A$ zZZ2GPaY;}r!qHd_E)JG8yuxejlE6=>*lEl2^R8JRMC7^!2%*+%kCl@D2150y569Y#R zLqk^+3jP^AzBm>-f^`VZk(FesbQk+B56Ic|OpnyCZeRygH z@!&ZkH4m5#ih$|;&AU`7U^a5~ba4#v@LoFA);}arpzZm+yR0IuO|yw9^3S+Co=iYtlq@auQ-1soV~Tn^!4dAd%e`+ z^V@V|H|aZWE37>->516s=Z^Juw^J52u4XXl*hlFdSzLY|V7<|&?Vs8pDLdDiWzMG|_8^3+orF3R#= zdh_;Z;1<1UrORrSGcU?&xLSEWt$26iz02!^VSJ|3j=bM?#%%TFG+o#Me2L`Ol4i?smEbEjB!Y^_=`>rl*WebW5nbpKm8<%b*PoRQXaO0w~7t%j$PpI8+pY)e=o5GFA*EzKdAM9CCYj>lF&Vrk0<{>O1*v(l_>i$?`06TD+htj=|H_&t;ucLK6V%;;2&q literal 0 HcmV?d00001 diff --git a/img/page.svg b/img/page.svg new file mode 100644 index 0000000..91f925b --- /dev/null +++ b/img/page.svg @@ -0,0 +1 @@ +page \ No newline at end of file diff --git a/img/perplexity.svg b/img/perplexity.svg new file mode 100644 index 0000000..4bf985e --- /dev/null +++ b/img/perplexity.svg @@ -0,0 +1,49 @@ + + + + + + + diff --git a/img/petal.svg b/img/petal.svg new file mode 100644 index 0000000..41e7619 --- /dev/null +++ b/img/petal.svg @@ -0,0 +1,110 @@ + + + + + Petal Search logo + + + + + + + + + + + + + Petal Search logo + 16 agt 2021 + + es + + + + + + + + + + + + + + + diff --git a/img/semrush.png b/img/semrush.png new file mode 100644 index 0000000000000000000000000000000000000000..5e15d0d2664113ba02204aa6b7b3f37b09c30b2b GIT binary patch literal 745 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGX$^ZZZ$^lrduyz0d0)9zEK~y+T<&;ZE zRACr~pEGmLakQE7hBz^nNDD2qG%O2h6DLyYxRLF+aw#U)z-#c`&g%uxWyfmQKe@2F7uw z;>|(V(KLbqI()RZ5(-jS!rsFS&NI}Eni5$aJ5gYm;%ZJ_kUJZObPRDilMD}bmG8sc zs-f!<=Np-xq}NCFRc5BRQbu?Yn<~ne!qz?bp3(9KcZysru1qhUEJ+dE=l3MVy_K=A z>_5VRa$Y~i<7Iahf$k_^38aV!5~)8$-9_rVQ^;ElDok zHSujoddX=Nl`|9h1OXKj&`?9(9#oayHgu=-LFN=EF^5_LrB%3+Ek`V_Jj2)^A8yNi z#mOozQ+k3gJ+wX`VY5}WVjva#ZEP&#*g1;!$?T&FEbytF$x$-1$Sq)Ej2oBeZ$i(A zzF+nKNRdAUe;?kXlvI#kEIa6Oli-l4{g|cG$BXNXyv31iWw!=sN#S|sdu3&EA*ox~ zkS?cYw43o35_3>pF^bS{K`|L2j0KE + + + + + + + diff --git a/img/vivaldi.svg b/img/vivaldi.svg new file mode 100644 index 0000000..c3c211e --- /dev/null +++ b/img/vivaldi.svg @@ -0,0 +1,59 @@ + + + + + + + + + + + + diff --git a/php_errors.log b/php_errors.log new file mode 100644 index 0000000..3705f86 --- /dev/null +++ b/php_errors.log @@ -0,0 +1,8 @@ +[03-Sep-2025 15:22:41 UTC] PHP Warning: Undefined variable $file in D:\Webroot\development\lib\plugins\botmon\cleanup.php on line 14 +[03-Sep-2025 15:22:54 UTC] PHP Warning: Undefined variable $file in D:\Webroot\development\lib\plugins\botmon\cleanup.php on line 14 +[03-Sep-2025 15:25:36 UTC] PHP Parse error: syntax error, unexpected end of file, expecting "," or ";" in D:\Webroot\development\lib\plugins\botmon\cleanup.php on line 15 +[03-Sep-2025 15:35:57 UTC] PHP Deprecated: Using ${var} in strings is deprecated, use {$var} instead in D:\Webroot\development\lib\plugins\botmon\cleanup.php on line 14 +[03-Sep-2025 15:37:51 UTC] PHP Warning: unlink(logs/.): Is a directory in D:\Webroot\development\lib\plugins\botmon\cleanup.php on line 15 +[03-Sep-2025 15:37:51 UTC] PHP Warning: unlink(logs/..): Resource temporarily unavailable in D:\Webroot\development\lib\plugins\botmon\cleanup.php on line 15 +[03-Sep-2025 15:38:10 UTC] PHP Warning: unlink(logs/.): Is a directory in D:\Webroot\development\lib\plugins\botmon\cleanup.php on line 17 +[03-Sep-2025 15:38:10 UTC] PHP Warning: unlink(logs/..): Resource temporarily unavailable in D:\Webroot\development\lib\plugins\botmon\cleanup.php on line 17 diff --git a/script.js b/script.js index a1c723a..8437043 100644 --- a/script.js +++ b/script.js @@ -3,6 +3,16 @@ /* 04.09.2025 - 0.1.8 - pre-release */ /* Authors: Sascha Leib */ +// enumeration of user types: +const BM_USERTYPE = Object.freeze({ + 'UNKNOWN': 'unknown', + 'KNOWN_USER': 'user', + 'HUMAN': 'human', + 'LIKELY_BOT': 'likely_bot', + 'KNOWN_BOT': 'known_bot' +}); + +/* BotMon root object */ const BotMon = { init: function() { @@ -179,7 +189,9 @@ BotMon.live = { _visitors: [], // find an already existing visitor record: - findVisitor: function(id) { + findVisitor: function(visitor) { + //console.info('BotMon.live.data.model.findVisitor()'); + //console.log(visitor); // shortcut to make code more readable: const model = BotMon.live.data.model; @@ -187,7 +199,29 @@ BotMon.live = { // loop over all visitors already registered: for (let i=0; i= 1.0) { // known bots + if (v._type == BM_USERTYPE.KNOWN_BOT) { // known bots this.data.bots.known += 1; this.groups.knownBots.push(v); - } if (v.usr && v.usr != '') { // known users */ + } else if (v._type == BM_USERTYPE.KNOWN_USER) { // known users */ + this.groups.users.push(v); this.data.bots.users += 1; - /*} else { - // not a known bot, nor a known user; check other aspects: + + } else { - // no referrer at all: - if (!v._hasReferrer) botScore += 0.2; - - // no js client logging: - if (!v._jsClient) botScore += 0.2; - - // average time between page views less than 30s: - if (v._pageViews.length > 1) { - botScore -= 0.2; // more than one view: good! - let totalDiff = 0; - for (let i=1; i= 0.5) { - this.data.bots.suspected += 1; - this.groups.suspectedBots.push(v); - } else { - this.data.bots.human += 1; - this.groups.humans.push(v); - } - }*/ + // TODO: find suspected bots + this.data.bots.suspected += 1; + this.groups.suspectedBots.push(v); + + } }); - console.log(this.data); - console.log(this.groups); + //console.log(this.data); + //console.log(this.groups); } }, @@ -736,8 +736,13 @@ BotMon.live = { overview: { make: function() { + const data = BotMon.live.data.analytics.data; const parent = document.getElementById('botmon__today__content'); + + // shortcut for neater code: + const makeElement = BotMon.t._makeElement; + if (parent) { const bounceRate = Math.round(data.totalVisits / data.totalPageViews * 1000) / 10; @@ -760,15 +765,29 @@ BotMon.live = {
Probably humans:${data.bots.human}
Registered users:${data.bots.users}
-
-
Known bots
-
+
`)); + + // update known bots list: + const block = document.getElementById('botmon__botslist'); + block.innerHTML = "
Top known bots
"; + + let bots = BotMon.live.data.analytics.groups.knownBots.toSorted( (a, b) => { + return b._pageViews.length - a._pageViews.length; + }); + + for (let i=0; i < Math.min(bots.length, 4); i++) { + const dd = makeElement('dd'); + dd.appendChild(makeElement('span', {'class': 'bot bot_' + bots[i]._bot.id}, bots[i]._bot.n)); + dd.appendChild(makeElement('span', undefined, bots[i]._pageViews.length)); + block.appendChild(dd); + } } } }, + status: { setText: function(txt) { const el = document.getElementById('botmon__today__status'); @@ -864,7 +883,7 @@ BotMon.live = { }, _onDetailsToggle: function(e) { - console.info('BotMon.live.gui.lists._onDetailsToggle()'); + //console.info('BotMon.live.gui.lists._onDetailsToggle()'); const target = e.target; @@ -904,17 +923,20 @@ BotMon.live = { const span1 = make('span'); /* left-hand group */ - if (data._type == 'bot') { /* Bot only */ + const platformName = (data._platform ? data._platform.n : 'Unknown'); + const clientName = (data._client ? data._client.n: 'Unknown'); + + if (data._type == BM_USERTYPE.KNOWN_BOT) { /* Bot only */ span1.appendChild(make('span', { /* Bot */ 'class': 'bot bot_' + (data._bot ? data._bot.id : 'unknown'), 'title': "Bot: " + (data._bot ? data._bot.n : 'Unknown') }, (data._bot ? data._bot.n : 'Unknown'))); - } else if (data._type == 'usr') { /* User only */ + } else if (data._type == BM_USERTYPE.KNOWN_USER) { /* User only */ span1.appendChild(make('span', { /* User */ - 'class': 'user' + (data._user ? data._user.id : 'unknown'), + 'class': 'user_known', 'title': "User: " + data.usr }, data.usr)); @@ -928,27 +950,24 @@ BotMon.live = { } - const platformName = (data._platform ? data._platform.n : 'Unknown'); - span1.appendChild(make('span', { /* Platform */ - 'class': 'icon platform platform_' + (data._platform ? data._platform.id : 'unknown'), - 'title': "Platform: " + platformName - }, platformName)); + if (data._type !== BM_USERTYPE.KNOWN_BOT) { /* Not for bots */ + span1.appendChild(make('span', { /* Platform */ + 'class': 'icon platform platform_' + (data._platform ? data._platform.id : 'unknown'), + 'title': "Platform: " + platformName + }, platformName)); - const clientName = (data._client ? data._client.n: 'Unknown'); - span1.appendChild(make('span', { /* Client */ - 'class': 'icon client client_' + (data._client ? data._client.id : 'unknown'), - 'title': "Client: " + clientName - }, clientName)); - - + span1.appendChild(make('span', { /* Client */ + 'class': 'icon client client_' + (data._client ? data._client.id : 'unknown'), + 'title': "Client: " + clientName + }, clientName)); + } summary.appendChild(span1); const span2 = make('span'); /* right-hand group */ - span2.appendChild(make('time', { /* Last seen */ - 'data-field': 'last-seen', - 'datetime': (data._lastSeen ? data._lastSeen : 'unknown') - }, (data._lastSeen ? data._lastSeen.getHours() + ':' + data._lastSeen.getMinutes() + ':' + data._lastSeen.getSeconds() : 'Unknown'))); + span2.appendChild(make('span', { /* page views */ + 'class': 'pageviews' + }, data._pageViews.length)); summary.appendChild(span2); @@ -956,20 +975,33 @@ BotMon.live = { const dl = make('dl', {'class': 'visitor_details'}); - if (data._bot) { - dl.appendChild(make('dt', {}, "Bot:")); /* bot info */ + if (data._type == BM_USERTYPE.KNOWN_BOT) { + + dl.appendChild(make('dt', {}, "Bot name:")); /* bot info */ dl.appendChild(make('dd', {'class': 'has_icon bot bot_' + (data._bot ? data._bot.id : 'unknown')}, (data._bot ? data._bot.n : 'Unknown'))); + + if (data._bot && data._bot.url) { + dl.appendChild(make('dt', {}, "Bot info:")); /* bot info */ + const botInfoDd = dl.appendChild(make('dd')); + botInfoDd.appendChild(make('a', { + 'href': data._bot.url, + 'target': '_blank' + }, data._bot.url)); /* bot info link*/ + + } + + } else { /* not for bots */ + + dl.appendChild(make('dt', {}, "Client:")); /* client */ + dl.appendChild(make('dd', {'class': 'has_icon client_' + (data._client ? data._client.id : 'unknown')}, + clientName + ( data._client.v > 0 ? ' (' + data._client.v + ')' : '' ) )); + + dl.appendChild(make('dt', {}, "Platform:")); /* platform */ + dl.appendChild(make('dd', {'class': 'has_icon platform_' + (data._platform ? data._platform.id : 'unknown')}, + platformName + ( data._platform.v > 0 ? ' (' + data._platform.v + ')' : '' ) )); } - dl.appendChild(make('dt', {}, "Client:")); /* client */ - dl.appendChild(make('dd', {'class': 'has_icon client_' + (data._client ? data._client.id : 'unknown')}, - clientName + ( data._client.v > 0 ? ' (' + data._client.v + ')' : '' ) )); - - dl.appendChild(make('dt', {}, "Platform:")); /* platform */ - dl.appendChild(make('dd', {'class': 'has_icon platform_' + (data._platform ? data._platform.id : 'unknown')}, - platformName + ( data._platform.v > 0 ? ' (' + data._platform.v + ')' : '' ) )); - dl.appendChild(make('dt', {}, "IP-Address:")); dl.appendChild(make('dd', {'class': 'has_icon ip' + ipType}, data.ip)); @@ -986,6 +1018,12 @@ BotMon.live = { dl.appendChild(make('dt', {}, "User-Agent:")); dl.appendChild(make('dd', {'class': 'agent' + ipType}, data.agent)); + dl.appendChild(make('dt', {}, "Visitor Type:")); + dl.appendChild(make('dd', undefined, data._type )); + + dl.appendChild(make('dt', {}, "Seen by:")); + dl.appendChild(make('dd', undefined, data._seenBy.join(', ') )); + dl.appendChild(make('dt', {}, "Visited pages:")); const pagesDd = make('dd', {'class': 'pages'}); const pageList = make('ul'); @@ -1013,6 +1051,7 @@ BotMon.live = { li.appendChild(details); return li; } + } } }; diff --git a/style.less b/style.less index 85e73e5..cbc3b89 100644 --- a/style.less +++ b/style.less @@ -129,7 +129,8 @@ color: #000; } details ul > li > details { - border: red dotted 1px; + border: #ccc solid 1px; + border-radius: .5em; } details ul > li > details > summary { display: flex; @@ -139,24 +140,30 @@ font-weight: normal; font-size: 1rem; line-height: 1.5; - border: blue dashed 1px; + background-color: #F0F0F0; + border-bottom: #CCC solid 1px; + border-radius: .5em; } details ul > li > details > summary > span { display: flex; + align-items: center; column-gap: .25em; } details ul > li > details > summary > span:first-child { flex-grow: 1; } details ul > li > details > summary > span > span { + display: flex; + align-items: center; + column-gap: .25em; height: 1.5em; overflow: hidden; } details ul > li > details > summary > span > span::before { content: ''; display: inline-block; - width: 1.25em; height: 1em; + min-width: 1.25em; height: 1em; text-align: center; background: transparent url('img/placeholder.svg') center no-repeat; background-size: 1em; @@ -171,9 +178,9 @@ dl.visitor_details { & { - border: green dotted 1px; display: grid; grid-template-columns: min-content auto; + border-left: transparent none 0; } dt { grid-column: 1; @@ -184,6 +191,19 @@ display: inline-block; background-color: transparent; } + dd.pages { + & { + } + ul { + li { + & { + display: flex; + justify-content: space-between; + align-items: center; + } + } + } + } } dd.has_icon::before { content: ''; @@ -200,12 +220,13 @@ span.bot_googleads::before, dd.bot_googleads::before, span.bot_googleapi::before, dd.bot_googleapi::before { background-image: url('img/google.svg') } span.bot_applebot::before, dd.bot_applebot::before { background-image: url('img/apple.svg') } + span.bot_openai::before, dd.bot_openai::before { background-image: url('img/openai.svg') } span.bot_metabots::before, dd.bot_metabots::before { background-image: url('img/meta.svg') } span.bot_yandexbots::before, dd.bot_yandexbots::before { background-image: url('img/yandex.svg') } span.bot_seznambot::before, dd.bot_seznambot::before { background-image: url('img/seznam.svg') } /* user info */ - span.user::before { background-image: url('img/user.svg') } + span.user_known::before { background-image: url('img/user.svg') } /* platform icons */ span.platform_macos::before, dd.platform_macos::before { background-image: url('img/apple.svg') } @@ -217,6 +238,7 @@ span.platform_tizen::before, dd.platform_tizen::before { background-image: url('img/tizen.png') } span.platform_hmos::before, dd.platform_hmos::before { background-image: url('img/hmos.svg') } span.platform_chromium::before, dd.platform_chromium::before { background-image: url('img/chromium.svg') } + span.platform_bsd::before, dd.platform_bsd::before { background-image: url('img/freebsd.png') } /* browser icons */ span.client_opera::before, dd.client_opera::before { background-image: url('img/opera.svg') } @@ -231,6 +253,7 @@ span.client_samsung::before, dd.client_samsung::before { background-image: url('img/samsung.svg') } span.client_uc::before, dd.client_uc::before { background-image: url('img/uc.svg') } span.client_huawei::before, dd.client_huawei::before { background-image: url('img/huawei.png') } + span.client_vivaldi::before, dd.client_vivaldi::before { background-image: url('img/vivaldi.png') } /* ip address type */ span.ip6::before, dd.ip6::before { background-image: url('img/ip6.svg') } @@ -240,6 +263,15 @@ /* user agent */ span.agent::before { background-image: url('img/info.svg') } + /* pageviews */ + span.pageviews { + border: #999 solid 1px; + padding: 0 2px; + font-size: smaller; + border-radius: .25em; + } + span.pageviews::before { background-image: url('img/page.svg') } + } /* item footer */