]t p‰|Z@6uC&bY{ .*@E΁ܹr+ ageOj߈c]zc nl70̆p̕|**UN.EcjrԨcM9fR16әSemH(p|T෎GXvʸLQoa`^i^bl|SfFH3Ȉrv_]E5qbqJ%1^5ϩF)3E07iuîSp*M'n(^lXk 1yΤ-NmU?dέQ=@ S,Z+rـb[ $nA&B䟁" 7KaJg͍i5/hF1 4PZ-0]Js,4|<;NA9Y`ȄjnǦid1+Lzk,;DF*ƫc'n΅Jqck22`ݵZͷ dۍuwcrD;1ݎ}D) LߞFtz)ώIJo"5 RWm'XsBIɸVK*cI쎏,kׁ*!w\4զSp0kZ2י^U4@)Cb4 8z*f5@9FNĹ tv%"V7J_댿924ѓv!lh؈r2,^Uxvl F@fY2\" | XO.Q1_CdX3F7! I\y-\NpB 6{pzj>yψP=1Pe vEo]CR%0>cW~, + H28H ewsmUK~AXneEƠOh~TQkJ+9w]"!WNkw>9z`4 {*-V\| =E AX~jL3S*v-D-gX!iJiUuˎ ^ߌcsf- =!;jZ~q7^A7kw/4p\d27x>5v[z8&5y: >BJYt5=JR=lRJQbu5a!&"`"BťS*ߪX!Sie5j}"fM^sd)5鵋&Y߫XC`Zi{֩E Mø5BRӫ s36/&n-JM}Q@ht_-K+boFVR(Dv;gܹ'70`RDWO)#DcpalN1S=|!1RwD,I\r*ᨺ僊:'{>nsW?ZK?YTHjjxW~A5D\ Ð.<|%1}V8wDE` e?_r]q=%Eհ-H3\gCE ]ՌK3(֗~|ñp0M59!RȻ DTq"j +wg/^šV,T>yDPVtmlN{ w9D(bb-N0>kd固CrOUFp@cރm!gvkcRn;N,YvҴX־+W00ޫLO2lB7,"n;3RgF kw=۪c)zh'8r 9(F}VOMT ̼X UKE}kzrR7 5Gmi*gmPb uiséz[Nĺ4n8eԙ$n:T&tgpzRGD{J:PM4 Ђ^(SpxuwC-#Ŏ*KDV4 "wQ :H4:*tlj"Dsq{u7O1f;@Nj4*M$ >pl#'̸qQQ鿵 ;4ѨjXjLEˈ霑9=*Bnw;eO:mʽy>! gW老u\$f8ÚrJXI":QQKHERr0 ] 9Us!^Re4rg-P n]ўf/P*'B˕)62|tF *xi*ca]b' kml-]3.Q:cyKpX"pvryr& 誠 c1B!4 ,lQ@ saF$(oJXL%v%aJ攺ނo҃= vVwRg{f_= y3)QEHO5p~03;&\5 R(KbT6=iVBi B\t|d&%L"uLMGt̉>&hy3 qg%d*gd;]Ms:I}\ϋA{O:!}(T_I%vt+rzRzkA ml8BU2͸EU`KGѦDz&f?w@٧v z? %2]=LES>|wW6 PhƗ.]1P:*ԸFMt]9a 2|u<[:v&:ͥ8NIgjsaN(#QdDP%(A8荢Yx3:J~\8J]W7݊H4|* ',la@e#(<X Uvfzk7x-/.x) -O/'qgP; oKO?WС;wSaA_U0&%-LE_R9 G]-0͵7,{b9žg0viy+⍱B$Ja.Ģ'n~A:q'Q:H&1bK;䢲ft|7C(l`@5@2تZM&CgUG\8.2r3k.K],w.rP^Sh%ED},f^uR ໰dᖗmFq̡VBkd88Mu^*A.>β2|i)R2u,H+Ȅ n2!4'G wĒz>q=+7Ucʟe:T"̻L*#ukWG #Q$f|WE0.&B<a_qg`t1q y8_5CdgK礝Zk5O˰p\ǬRAV!i)9*ZXm d\rdM*s/Jl+Iewߍq01♬0Q+7}p\haaOB3b<ە38Hk9cMr bWg)| K* fYQLG~ho^AkxScPM֏>ܺ9^N+=q?x`E -9ۻJ^Yh jECV6nAczza=4ZR{-3=̨5`z:%7 .g Hwݽe:-2mOb; BdHW.֗13_옵62(2t0ԣ-Pa#NxilZ5[}mb?|gc-sF}~z H%sTBhb_'?Q`  ']T zlyćlY)_6'jǟ44LH5q YD^>aFXnR7I$z)Y6Mi"VANݯt}v>^BuE(, (%͡9B.Wk5ʥˬKoҤy LME;OWa236:#* u$:ekנ%0\=)ޫ\:-i, 689cB!WJde*? sr" 5 D$ՓKvTǶ\$& ^<nd^]=zCݧ@w%og {K, ؎& =h|JEIջcmH~1TIdX]+&[JK9nP>ޒ;$\}t;._@ߤBC 㣈 d 4 3py͒4.|AAޯF Y$5E^d~w9: Gq LR le/m _. Lʼ F+N=Twsx=cDV%0t!l@Y|μ1fT(c^Q:_E" xmC6 /oঐٽSggwVPЙ„ڡ6$_ֲ/(ju)x,ې $z;̆y'ʴ| .i }wNWe(:o.ǥGVbØP$ }4u%K{i8b=)8Ɠg"-GR)%56漀>;%ߐX6B% M.FZl0ۤb|Msg [=Cq)}pPV5#3A;[~[‚ U]%H\̰a'YzۀwĿ.roY kտxW9 uAb6g \_`RuO6Fx.CvʒcfKv ̺lgMTu ?}~ߴFP̎!|n?ikRR<]*@P@`22fөu '+PۤwÄ2D#t`ހxϜ.wL$_f?M&R?cNf8D,8>ȨDѣX gGE "!fVmX%Ɛ-ci\w?yv2}rՒ\{/Pvwr~~+K%"C>4Xg@X t*Z 2V H#TE#3M/#4+Rg7ti;WUܥ`~$n\\, _҅9zb ?G%mTfb= wtO +k_ =OZ^ zs7w>e;iR|#9p.m׸ܠ^u.[lxLٿpYaV*ȕk 4 }15r-&ahK ,&ͮta2iX(Nxy:?v$h+~sfo@ďwC9'4[) PbTIJ^TL-FLyM0˖sV0L)[@{J*wX]*P-op.Eԓ׿t4rM;k&[PVe+jdFNfcE4e~%""gz,S lᵬU r ^dWx/<\DRkOuy̳3apztGbKR'!xEzZyx:WZܮkVr$ÏGys1(-z%[WJ .ͻ=^UGrEKU|wSߊ'| ޝJ͜9Su#Pq~Ɩ'u_2ig~fnϸgԪa cQ~ѴɐI7o#avc_9t/.VrȡTyL"q^#6+$ݿ6`ԳlM&^ l |.SdL W.'܆YOSx:/j7:TH xog6U@x$:bխJO|ݢ\ì_~3f@ dPL1gF2r!Ed ئ)nԝn "F$yO@5WM,yd}J=21 0ͺ EeIjgX^#+$BkDV.{(p]7#˰伹aWHӍEq&a% #i un8p1:_\E ­K{-HNfD c,zc#Rb|C6pWE`2nR&!Fàrj'NK8X,r[sΖPa3h:h6*kF,&Z8Z0fO lY/`>8[v$Pc؉"%GXi4B"s]t/FKV<Da7r(ӵ*+WPP3uU=M,?ػ+S,(PqRvM HL$Uy9<7T , D=$:쎡?O y"Z}.vBh›/hAZDu b:VDI$M7H6o}Y'+;QRfɀ/h2 wזHjl ezuofK:qOM~qt%D؂qdne-e) ٍ+ i@8D)l؞$?]j$2X7Y +Fq#u]+δW6 k\dsQ #+XE3+~r(ߓt吙 n1c:t⡉aҷ- EHh#f,!=TplUDs|w !p)Ŏ%<{}^l5~ &xmOm& C+a2Y$f3r62j&Ij a]MG`Na_&=ܞI|p,aق-@5y D[Ѽ _K\ b^øD'ZmT~_I5RBcRK\z8MeZS990\Fl X/j &u"Y( C;ӑeN(#*xYG"=LWc"=QAѽR!o̍bHU$>3\1TlQYYKaV~cMe.#D#طʤvrJE>>P1@wߥ?QDy-9wg@ zm1wYi@&uɌejM-TTg'L)}rӬ9 %Gb5@4.:~ "_LKE+b?aBs⦝N3u!#X҄w2#TfDi'X޽\4Vݤ-Qɭ\wIՏPy4XˈR0<%ZP:dٓaO45T LPMla}d/٩^`P/ܒlqihx.Թw>x:LyِP_aMس Z,R̰3^.k"p3jN"~!Cpe@< \/f(T˝]ʎgۨm fE.8|,fSUz A AKOBi>K`qGSˡ|yn{ LgGX *ԟ&9V)_ ]uTe^~!)N} W}wF"Ԋ֠b̈aNO!( s@.N5^~0@b4_ύώ 0Ymu0ŝލFU@!.qlJs iSQdSGUҒę%|X1F . ql-ݓuejA>c  Ev9˿?ձOO/!N5P*"#=!g}%ƚZG_WS¶C 6jn3oD*<+"EB(=)`(/ 3?_7k܊^hR)ޑuiJ4;:} Ba94m B& H Io+g c&43ѝ%$OPv𒲸s\9d/_Ѵ vuj18M9ԢRpU P̈́woXπk!,Av1Vfr V_*7+{^8óR5?!RtCI$jEȞ 9j.PأIH3DKz?0VZjHbM:A,|?e9  676< .}Pqئ a*eVNT#~rdk@99$M.2wVDW2kT/8 33Z;I%-hxgxeU="h&N=GT4$d4SwmXPCUmȣܟ\ՙ}"D4>%Z͡5)a"U D)ʮ;d502 )%PT0PS`-b}>{Sfĺ8 oʓERxƹY2En׏@9x9+q*Lt,lEgaG#)Q}L sڛcQr@^#16Q kM.p*)QK u0!cVԚ6;k#qU52y U(HqWA7$XTo~DSPL5lG@jFvj`:h\('w!OԐQ#XQO9p/w؜!4!M58)U.)B]4Uh8OzEyy.uA1Re-F7p!J04 D5HV\lG ݧv~C% )ueW}ćp鳄^rDWnSi!'f?ٛ-/zj:xab]K'r7.o 6\./ǗI k9{~[}+Y(\/&V$M= aT'7g\kE=1Q1E'oޭ X x ;A^uY|oߤELy%C6 ҈(}ê\#mP`5 Kl]CW"X( naHXHdKo'AqdC;}_R=ͪ}47'C3GCŖh oL,gF(l-V}ݷ,2gl:IjQVy_y[z>!"XM4nmPv*N|@y6 5N1ʡ51VՑQ6XHZW 9ٰEiJ#ݖg^9bݨOå:1E2x-P蝗VV{&ħ 4BޣP“.V >E{yl÷{:fZ%xVaj\z$g9H*#",ll&;i@̲B,?9ᕒ&ޱ~Cbk rWTh^f=l4gykڣUjvOh0>H?QLa.,޾g4ЛIǫE 1{]QW,/j!es4m; d>Hį[F*qB){S.1#:9k3(y7~:r31ثݦKgQ^tS-KK$4> 6̡zf|7yrP'_kqgѤ!1\~*9OB%F#e%`Rfۮh(眤=n\@4uDށ/؀Up@w\B%?fX"\`CȧN'-P#wc7t/v1ox+by&a >?ߘ~9Bҍ쪤+Ϣ=e]{02j-/[@W-<(ME)Vk"-y~J eW-lwO}SVdM@WtԎ)E:SBE+= FOPF0N%oGRn+(jk=$k<2Ƣ?%ILkmi6颷Tx(=E>)F faI, \,9w*?mhs#WwV+vO`Pԉ:m|/DP= +$P%u<qL:6fЕ]U=?Yg;g.|쏾<ىӇ~Svji8Z5 IICN2u|x3k'"JJnR]-Htu'QBe*6?1Z_o/}Ž&Et996PesY;W|f>Ycs|Q͓' cZ0Ja#xO"X+ ?2/T"Kch9o``*.⌔ |0=spo9tSjeWӳG0Fwl'IH uȩG=D5+9׺AhZұͿ*qߨ1=O4d/x3BĨ!,rq7HӐ3i$xcŪPkhR'+Ï&@z蟹YGP=0hk~F 9 owG<&VDfd$# u8"Ad0Ia0;;ٜ^T:SdK/(6Z 8 8΢D}Br);Dy<~_gĿyЊ{wի(qd(X:lc.N3< #{/F#mL7PQK`V$Yt9P>AvYl.>!H"Ya8;߄Spa <|ڄǘI}@.m(B1ͣR@g`{"|ыWԿGFeBq^BI,Rf3 ӱZQSZ *si*$zN,=3)zJFAN %)[`BO>=?Xr] .eg"5;!O0Z[b!*:?}/d'}&kjoJMy ^pgxLs Q2Yd.nғs0Ho<C2my4eDs5}`J̒qntL!s]O\鱏L- +< >!F#dWKaxus3S,Xޏgcw)il[Nj>fyZsS ]$z[ލ\Cdx e> 0RV[Ncwht߮\s@iJzkŸa8e⓿O26CAU T*W^*Z/U*|#'OXYcM<ܻtgo!lLP f<쒅&G "BVqny @,zC*߶`q}4EC%qVWUP*i¦G<3IFwxF(/_CcVE\q f Q"~P>Xp,)gf%ɬ#utT =3xﺫa0͕+64ȣfM F;̣$U%*FT%13M!1>' F -9oƥ‹>=¿*`҅)v7A oM=V\G|˧SSg-*SKr}* DszY%m0-*amzo/v &r׃OcJym_L>QA uLBAʖN?HWvZaJeLjωn "a5d|cB, ЋuтHu6*65O5LMbyJg };,e+bx&>onbB608I޵x |qB-s쥾Pu*Ӭ`7U? ~a XjXH#l?t;2?Hwl&&݆5ȅEYqo4KuOjte`)I@.oY$ /wC@:v}>M3U%\oE?"3)4: Z?`[ z3U=t/bϠ|O2k΃gp^K/0m{[7Kx]C-{O@nFDGltzP&<H$DԣDBs9*vRz;knfzX=aRd[ѿt&`Jdpoמ+cf%.ZSᤔMs.domH>R#R)a M5ju#H$=1!D ͹ά'ta'+8GSκ䪖?sKt4ohlce"B >hkH65j/܋EIK7pZm$6Hͫ!nbbe+}hh5ȳ+_"'Y/u&N鰠 htvksy&v_Y'w(zܽ+Ժ4|nj4@صN|J=Tq=$fKH3!9<ti5Jߜ $SdnwG `R?&bЊhPrk)9AtR*oqAڦtD39nr|⏹DJm5Ǯd}n6MߘEXYI'ԈW*XBU{շ^ћh)A1J\+?[x`/1=GTi4F1?È{6;8rh oL2}ȎRCꤩt[AH0A75p\/u<ÂE!\N=.1;Pq9=IJyҸ!-ݠ x[ZhuFꇧnsb~lx1)<0n Ш6 _*f+CK\R豋)4צ%W9aĉ[\¨;S᫺KFb1Ԣ`ޡެ' F>?]HTAz8t^EAH/jDrҖ?ֵA$YS@h4X 4QcٮPHb,9Oh <@XZ P \ԨzNKs&HuF[=QY\"ap^36=дY/[9b9#L^q4wln>E_o;~2=Yl2U޲XxÊKpNX1y\L#DIsak&ڷx",?\-P쓉Е %U ԴǸ#{ !lѿ9dZK4+?猂B֨(GR}I$zm f 73Z?KPkq\@s~HRx9 hNm>!|:iG_rgMy#ló *twTo޻F"Lo)1A::6Vq<89:.j)9u)2%`,<|)[ovRtfr`6,AY{TG%뻙s1HU;Cԍ XYp)nDb~!*|f^{9(b+.JR?1.d#fn7E7٫ՇEiZ ?f(r/ BcRUdlؘ9>k$&9em d(-'apuy!wJBDbY)fGjAvGr?XOjHuiA9FՄ}Tꛥ`Hcs'Jʪdf|[&S`W`$v@w .pT_i?o8lFwLBSFΈ}^E}At@C]U{B4Y2PψHT$$NjGzZָ#w F!ڢ"ф=ETΈ4L _| ~#i MӢc1Mb N(L2af<Z $&qhWt[F,{y| DmeT:F ǧ|oQ gÁ^6 AnbvhP݊ʥ[z.JcMKT*"f(Ƽjf;F,I_8ֵ2ӶzEj fZNpo~a7-%udkv7Cvѩz R?}:\Em7s8)GGQ5=o_+:|$=CW+Nr${N"#s ({Gm&:l5`M}U(,Ko53E倛e:R YDҧy" 5J̌( >D,huRh*x70w΍F5P[p:f lFW?_лLylm,+VOM󴣅,"<\NR>g8PgB|EtK/+N@ǪZ۩[4ruf7iR  oN8OrC['P"{uX}EcMQȑze:Kj:˳K4I1{bd,rS@H;C2u~RjB l8cߘ%fE):i%!FxX-=tڠj d%Xz[nTuUEE sak'Yy#TLO Zm]+V2ƣ eDIj0'gBCqK8V B .g-4=[?ߴ7кGbBW@,k7`g>}qqbs1Fhn$UzX]Xbq\20S 'h)P rr) 8O[ʵcU GZ1W\93*tXȆY +Tc[0]w/SiCԛا36bI=W#"-G E&r\5h1vgJ_; |Z[Jvun2zk1 V l~4֡[WN ltO>!_Ӈ:C,!#SSb}T IC?ү+ d=wɼ4o:xqR5h&vǴ/6v{ٌ K3PJ}y(6j29;Bd1˒2 /vGT"G"oKFQg g0!Qi|[ \oH ҡ#띓s2G ^]ه}vD!xy~cO@%2ec67;1E, E_at! ٹP?Oy7*2 .Gg <RQ(T3n uM(Dv D-uS,ʩ2[[Z|zomj !{vG(LVo!v4ۻ\0ս(\"eNC+Vyڸ`y{[jLod8[u~?K}6gr ~|e{ܬ><.rly{!rhvuf=N=I5_8aTr>ff)Hxy.f)VG Bf* U]c|w3T8EkPoP1߹%)/?=&?FwJJ6%fG;4S.Cwf᳒x2\gH l`6TVjLiWu}4V"$29&+xO$g!e'p:tfSCDbd0seI> FS䗅6ۛ#JĄB!O96 1L\/b Ub)`b{5 N֥SK)"8\-WvjT/rX! n޳xn"oc"ax1~=t}j}eUǧ"P=9=3[y9nPRK;zSN(fN;Ȓ?#`Tfm?mҙ,X%[ *pG"+ux߿dkE:lIX]&c٦D,)q$)6Ť9%nZQ:V;ˁ,?RVE1Oٞ6qih] sԆkIrTrQ5ImGuf\a4sJTĺeDC= ^>DعŭlhҘ <\^fhH @OܕFs6[+f:ApeC5uHSNw`n9op {.!§x&nxt_`Ojè|YQ2ɡѠw7M֝*u]nYy47"%d@6a0bJ0 0mYJ&YBkQcMJ1 p Zdzۭ[˅ yE+#* oV1 ɜ)„e") juDR ʱsN.%{Ғ| rP6Pc&xyƔ4ݓJޫdBJRY=Y_4ogOUUm>T꫑ W& 6 '[ޔj+Qal?\@[%-%t1oQ-]ο!" (}恢0.jVXAѸlsw yu P\ 0QJ6x'8SC4OGn2ŝ'ƧY K\.,O{O5ckyuU՚ R $*#]%U)ɣl:C=@v-jUDiէp`G8xa闿Wr $%<4QbsIUz2fn7R> %B5N_3x^K2,٩Wy-. `۰LϧC6iA}UeJURUrADҧ9q;~?iS`hR8S:8ď.'I> ?QbgQ y6SQ.sBteP]z*WW Up9}UF@U?JLV]_(w6c&ġ=H~ø?ІF/1y.Dܱ_X3N$OHDU}Ճpܭ+w^ df]T1J9ʧbL_ Y ~IճsG)m2m靊/~ yn{U3ę ?mNT+.TLR_|Iv.1~qQbh_>~=Lz^VRH| ! x bUr2iRw3%(\g!q!)9v[Wn-g.7/Mg-Ա{ٮX%$CbapI6Q3wUl5pf?BmDElw.65r`b9frN? ǎЩzҢ!rToS!k+À).TXd $ M9fG!݆?J-ndV?}ܾtnUO/5 X RPmyY_9` ݿ9ճ1oWWSM.[E6Q3cH'LD92M cZQXi&s1acPZn"@ƍCʒŌ"\Z$c~9 %;w*ܟՓ|okgDB塹}w;W'Fa.qw(0yZs=.iMJt?4I#⏱h _od\;f7q 7E 7bq?c&vc.pGUIS\CM0H|UMa7S 6d%/'lS?JH2p 4 |itHA͊D-nA5]m3Vc(FHD9(bDr2+6`&=%uy`5`E,cW1/_+(ɸՕúU "ҧ* AX16-1;DZɣN6N\F!.ڳl Gag#ʽP$v2TiMtm nQ_aHRP 1Z9r,"萁&odH1b8)})Ն~+%vpbCe]pf0X9Bo^|N+-!yOA(!l8m^ֵ2![.VF4p[c%(Ğa2#$-t |)vg g\Sh׋Nǫov;Q׌ք'/JDe 1AvÄD-#IJ^xfe@Y;A׭WIOښPJ6 OWnt0&:P upC̷&p| ;qBkٗ@ZnPtv 8u 'rpou.w0Jj<`OFl&Usya["ՐS庙yq},"’0]i<"gAF $i}Zp,@\bnR 4< w{H/GuC,iqoz߱iyu{`QqPF@ auVuX,K@/ XȲrHu m?{tpG6GDuUg!P6#k]ϐLe7ZFݶ3,I>BPmi4[? )m>n&ܽ&V%֧X $K}ze=Ofa^"(i]r*HM߆}5ܘ{qf25YjFZՎRˢ fU=Lfw<ƫj+)qg3ϧ̧T>^Ú(nOhțw j!ıAp)q S:LJ'[J (DSѴKN{zhEj@+*~/?)ᇄm kIwY7wJ]hH@#Pi0Plkq~MDnE\es] >t@6Y5r-(9j_t.[!+^n0\t+PiRtU#Ume1:* I1cJľ!u8kdGg%C I}? J}NNHݥ A noC(* NiBd"Gn~ڬw +tṠX+ MxsF"nP D.!c?\:Ͱ#gX2tU\=EC$B_~ݎȕXno2\ӐbEN ]6Q;IpXX.1> \m0,/ z f~ TbR<a)Dfttydp9/;ˊ*1:ow6Ekn9໪>꾸g+};IWk$h8-}+/ vԮţuKȻTv҈7A.JAa7 _\|wPc,1}3 Ȇa="1] )cC7\]nRߖꛜ̢+1: pi1`crhօ6Hn 9gZi y{D*G#'9혽 NBd'Z>z,}{9甾Ǎ8dr Z Wa/_[wR-)׍-%p<  $UKNIޞ^XOུ*A]E&u"+;=JZ Lu/yGKc TfU:e`?&x"a^G8sdޯ1z4@)[hÅQzsf9&) BK8 hz;OQS_,0'b^$>_.<UNSdG t\I2|DH=ҳq6'$FuJ`MMr hk9bDo ˜J ,$[0bԅzC"s6mS} &#/0 [TX3g$ %t}^F߶O9&lŃ{j0/!"pazDK=0$Z>]=BNKPA7Zf/momW+Wc2maHl!8mHp]j5&[yƀw#"")+;<#d5>[m4p]`TLhiT肄Uc І?V`ӊ-s~͢VI_c;_\֚;+OA # {'͌U훟ٷ` JZM!҄)IБKwU`룞-{9#Cve;S`hUl0y\-n<}s!%bWܯE<$`s]+*C /nxo\(9t<=&D Ӕa$NC_N܆D\Ÿlz񦭏Vtx ޲ tdF n N'YE] }]E-x8g a9MH5+^W A.='pvē60;h͈n|Co"=IfWf"S60ʹ X|Stt'h]_!tH_Ĵ\9\8&a uGZW.8ŕiNY˅"*."3nԵA^f [щc ְ}Dm=Fd@AA"]|r{Â]jQ[sILn0+ `Dx'2c,seA9Y*y;g_L4ٸÀecOA9Є i Z2 r"yMePb;w,YzP iOZLvqvնR> ! rL#_K\.:&d{\rկ&*'.3݄B[~@r(gیE PHSV-]  Ђf*NW%F/6^}cҿҵO( X#ߪ6TƎ0ͩZ[첌A,´1Vo4BR8S0Mʆ?BrZ)kٜLR8?Rg1kVfUB[- LCKե'8c6h,H&@a4u>~SʞiOs9Aoilh Fα,% u䴤̆TaTZ)*o{7Ẋ9K뗧H(FHiR-(ܽr@=#D&@q֯W+N:lݴ D0%\؆*aQWO3R lKX~1@z5"%}}UjV*!GGha1 [} Ym\wETQQsiXWx_ Uζ5`SJQiGV9֛$qX{#y`2 HEvKk3L9V9֫wn?"T_rLv$2p=dbqe$ OM}R?)@TW/0d74݂W9dSPV04o% RC){~m`7 u6@ߋl-abGcnqU[YΆ;}10#6~Cka(~VKE}n u=ۛdC崳F1֙Ckᔨ̑B A/"*g&Cr蓖6?+,ѫPZ.Ai{׻HT&쾩YpPኞ1P7fo䩑@AD&VZBNbH/ۤTnĀ@m)wM21l< -ʣGrTH3'cG7zz"0D$_Wۼsq[YBw^u?dt}n2=٣*ZԍrԞ€fV q¾x,w E2J3s Bu/^XetY ÿ>Om}/}ؼHJ?i E'_jʐiH3sޒf1P!B\oʠݼlMw66$ ~28o&wS*wP!@)ȓdQx%yI70s Քqx"/kuy,!28sEjΕ-D{$Y6u[Fn90s_Yn7d$v }h;IO^ai3=iYe|Oӽ19F{0x䞁GY:BviGn-8x5jU@4Ar*.1"-TK9W+3*O@bӦϽK&]Ak8\7jtKqp01hY%~<҆Z&j6oGc)Fַi:u$%We.ˢ|)[RZ%W78#tYŞˬ(peKw3L8֤dՊސCO׹)D"VCFoP~[sltg?l=?KFhn(^_sM>,j:GːKldc)C$AC;^:g7~Do%APQn:6`mݽfR0u{UkܝrY.VxcI@@=0)0Bv\ir2.!܈)~I"1X>2"˱px+eF|Fj`5E&Y=σcJ52 P]w7˘Ą6Ք0a$]Lj,{tD(cl$d CH)JckvnDBA#鵦$xy =ܣ*¸DI#<"˸뀞7H9.Cºkl*?Z2u|;w4lmq.84l 5pjr酦쥪d"RG&ݴSbdL;@ &8e+"-5ãhR6um2#qG,o8E_;f C|O<^ O=ܗ>*uaq -5ųu">၎eiwP@;XC:iD㍪>ejs߻Pg=eO V*'::=8ꄿML#N`u-?{/_~PvNw$!/K$VœM90/jYDmၬ[}]1ki8YG.w! k,rHn&iN >N~,8N-`n֨ آz^M i,%1~?*#RP bVcp ځ~@sxc[[,;΁>[D}߬3c:MzGL#f)24Js8t Uk,Xm+2ɢz WL<,sgަNkqkE1;zToTT0K}T\ q>w> @U5Ux s Im*hܡ eXGbooUypܡgA ZNHf( /,< e_ ]_Ϳs=F Ga_nx <3fYZOnJ*!>k 2ECr/ 1%?J`TT*M6RfuןK +RhW5ӌrĭ{17@p@}}0dۑ%k0 M8 WA`,9H;0z.6ܙ9֏z*,,0qlnPr }A<ֲlASb=4Ⴋ+)*բW)A26/f]-c%E&n&"#EU\O,?"Q:WMCkۅ˃}[#JDO +fHp"y Ci҂L8fJ7]Aq}C c9T'= hpf+vH" RrYCx4>l]!7-JCpEi@{ "CLX*;VHadLq5O̟ y|i4,hlSMw~}ME<E,9yrZƅuѣ+}cYH!7Dʋ9ٯ\zIm격A {\Ͽ@z'ᓧBBɼ*U1x}l YLۻT6T ףdOCK`_N"F]TG|&q!ZNnď¿Kb/Aap8a!hпf=E#ҍۼnIUG(/ O^>_BރnePCyWI;,z\/,֫ga⚿NQPumDzmW1#Bͩ"^E,xc ew[7S⡭wx~L{Lආ+],]Њ[2ehM4ǦdcJOvP`#csAp<\uJ*+7^oMu|~@ݶ#6RX^N?Wҋޘ/m|C$j1'$C8Er9/з LBp6Y0x7/lw$);an[ T-^ɞ1Y6XŒMms YW~~[^.l.Lp]vb%%CAZ9iOwŃ#v k}TnޫgCdUZI%"Lc6Ȫ4uDܭӳBv j!}C}ft?-P^"ᠩk%\#_S"N>;KӕM=H5ғ̐KkB0 EVrH ?ӿj%21[jR'}wDXCZ|1=E>!gR3a}ȟ'XƌE8_`3q+f4j>]qok_wnb.>"碌v.Y 1Öl?}<q&1S 45ӈm$geOyplYJj2 4 t8&<Ȃ̺e]̎.ٲSKC҄Uk3|fqֈ9uqу%{!.ss ?U $'>Dei>dAFRx 78qݞ0f9Uè__Ts,\0{2 ">@%<~B%9CY/ v,}ANXU O+FsM5@#5<1=5aRX1j*4;I#gE&zgUCb#E[փ( FJ a.$q$:P*=0JkxiR5o1.)Ɔ!7A.oG)ɂ b.wlʆ%u٫Pp+1G3tWgD2;kXXj}n uQX=PE(Dǂ AYQ:)W, g'Et`j; Kwczb)/{ @btIK;s}`‡QQ΀4Ti#u',]_<`54%|gH_WXTxZQ|oז-ja]d"GwV솹\ i*8Q{\Xw~ҹ&֌Vl#_Άr8ƼS)uԀ"ij >Wðˑ>SUH=,Dz9m۲n^?L&s瘕пH02ԗri]~LEc L/`W& dE*#RjO{᳇l]􈺨jJn͠3BYžb*$R:;#pAۧ?e'xX[>e̚œWr ^jE r9b߿+LK)AVvsݧTmt"˖y^ԡiT=+<ˡCMW*}괓:,3͝9 [k7㔆ӭ]="5ϔs"9N ;ҢFÑpei'1Vё.${*oϚAn Im4!:MՔO!_5_hH&uփV^u?(=ٓ'Zd͋sn5]Ì=`6ޘ@,(vwfUzxS)+}סFQ@dpN`Lqp#+#E;IA279rţоJoAjX-t螩,;O׈c+Tm'<49+yY@L]FZ:]/Aɟ)qFP60 SH$\qmli!,l&P7ع/?΅ˆmPlk4 ~WW-B.7Xdk+'(]y;k0vΆp+SLd>LQhc mKTX(jv@ԷīͲS8JWKzu]HZˮڬ mu^l`ҟV\5hƳ=~\֢+%Td,AJ}VN”dΥK ^jQWZ{7Zb;CdVx`<d,yUDj 1N-ÌƓE߇]̀x.϶M+;G/}.W#y^Xqõ ag匩;VVu)2#'Dg6VD@x>=Sl'mru4!'>cn~Dr[1h  0E?Qn#C7þ =D|&d GV9:mE9!96;e/$VCg/.h0'QV008[[8 E6-BЉ\ bױ8B3 jlE6e,;u7 9+lsTDU<;a(E4Ym/)U5c"Jx>*KPC>ڔ3;-%<ӏc^4i-!A3gK$pz:bE\"bouCmOfkB6dF}Y wv oE(W0 :“ F4)JSzLp9|>;ՏԱ&XILꟗW ]RIP9x 1ߟ7YNnJ8# Yش9DpƑ+x!¦:Yr6V %!2^;)9@_ -u3qGDwwgU_UWUY+4 AפdZ.ODFd &R/s#OpWPhN==up+1p:(*c8@rJHLxPo F-" 0SdUv(^*8ROa*{3@Hi83FQX A|SnsJ1VA y SYeqQBlPI1GLN\T<ZGaCڏN41ƂjCDV|hʳn$Z,̻B|>a[od@'<|PȽ2Yje8rлRMBlMnM ɧhRrqj0`'@vN?y?F>Y6,T-.E‡ LDiq;P{vL-܁/n- Ÿ;dtyh:"I猅oXp)mKMUӜ/n3W\p%yM[S`zl+?iH2 +ReL)'H,D><k VM#YpA5 W$zZHԭ;^.ɿUZ537A5s!ԻLSg]Yl˒nDaa{qt  =+7O.U56>x Xr!$- }څ'hT$"e}JxE^Yȅ3Qf_}c>u8tymqE_YDŽ^9oCSNU#;ߕzr ~6ꗎIa2, oJ̸! u?yW/R~P1ը6qRh5z鏆&)pBi;ˈ!92mYӋ7_ډ"p\gG nH8Ý%2PB(=8nd!'X=QOUkH \:;7(´QED~v`{q蹙EY*I=%mL{k;6,Z -CYhz.+KܓaqB=. abTe . Hqx ܔ  Tpp-ԯ'A^+-T| 1Mh#O- Jo $(bIhM<$4[u@YR0ϋ۶a ""KnG%B Cxz`FWrW6rBm 8niK^oV _Gb^D#3@̆M.5["-B`1c2zHr%2%fy Ӵ6Yâ[P%;5!LZ52{S0}b 0[ G?Uܱ3zC۹$ʑ%}ۗ2NvTLLrptE.]:_PZun6v~lX Th2, vb$4 B+nOê8j[о#AT9 'M[mIuP>L>hWW(D8#n6+ 62ciQ+ %cx{bdP5 QJ?A3`ESt^[KjEafS\G[O={B[JI ӻl.HF!̘J~:b3(J U[~I53֙JΠ 4k-m]j#J)o|m*" dzt1#~%IUR9)"6˟I#Ev;B!Rs ҩ4i[u]k[ۥ/?ygAmUOHةI6}|հg +Ba<\Uq˰}Y:#xbz9wp#QNF\u&mݐ9hˏ lCτT KR`35i R "IYҦ{gs34G۰>ߠqK  ?`q,"Kv;F*X˷"/w5E6Q`h_]O8֫ ؃劳b0P57mTg=ѽn!Vm c`x{K|U+u;a ze߼@  n575𵹨 m@] E 3:Җ1b8#X|MO3*.?_AQL5l]Dwo!2iBT{؍ %![_ZCT<"H'_^}D{nA( Vq8 h,rVw`GeT$ZȊ3C!?>#`ZMH1f"8)a5OD1|j } M^{AI̵e &~)n!ӪS-&b18S퉔dЍVy[YW~IL%{4AܚU+\a б(j5 yb\sʼO,g~wE ՚YJX?uYfl>Ci ~#[#+n gW|#!a=xpb_manY91Ax)jëhW2c(`1HOU㞞Z3%Rh4VFk*3SLzD#tpavXz6kF>خo ڔ]4}dBZ)٠evnŽ, K3ȯ"bD;birxVVmb[%Ft\%1a'Zj-!ds;=0A~5ؚcxA?=ڣ=C8d{dqi"9ൂ_əyxxOrB&^;s_TwWBi1t4T9[yeJ:} 57~s,fBqޖzF*G9_Q(z U!_6rHAь09Ս7xWOlGdBH6oЫVJR"CoXyNkA,}WϡebP cchd+"P Z(SJ)pR'~Y7InO]˗(b)j%&.ҁ$Uv5y# L1a]pa0fz@Odݙ_2kzp(i[MG8u >(ܮnJc xj6N#J2`,3A`tպeE 4=dg'O]g`?,퀥2 FC-c|3P8{q>`;E=n ;v?#ѓ-ѩ;}tvn|z!5@(X@dhH >nTm弣8̙ߟJfs-_p?,&y-Y?,RN0o˺$\7!ݦ Tp| j=QLTb1cjv҄:U3ͅ&!oiZřP3\|%7-M Zzx"Ec-_`w" hysmlxO)أ^p-W$)oOj3NղzZ B>TQ/1jpvTz净0 eǢXs V ئްQZͱAe;=\EvR<$,rgUa+E] 3,$ŕ((h*SùX)_J/Tno{cOg:gdjMo&ދXq쩞>kBQ]KYt+: bvq/ lPAQc9.i$ niٲhqОJ q+/*Vђ7 ,"Ziؐ?LjX*X>\]#\o+ܧˉz||Ibeƶ8/M2z-IJ8o7Ka<uf Qo"-q'X9:*E7caŒKK-.mQoQ 0iQ!_' ~rOX;F,YӞ!صa4ъ(5E-MaqjHڌ ĭ4i'XI0d!Z.vR̈R+j}o !ЃH>?by&ѐBͯ?wsh:j~9IdD+R$KfA۴;yR:'q2~TBuM,Gyu"dޢYwcsHʲL+`\LQgEOoH%s!^Bi+k0ǘ7qc "miaB M{(9MFu;'Fge\)b;cn Ojtx+v~0Xbgg!X!1Y3j+Z7{"]ϻ,nf u E"@w~ƋF 0?q QN.0T]DlTLwd 8?Nb(v"5ޯR .F1 v-+␊W&x+e@ahF 't䞴gۻү |O s9+зicNA_(In0z,OSZۇSPŻ5 w KcO9/~VV` $?JqP^f{j: _Ctɉs_[\JX}IX?>@I 64}+{_HYD)? MIzMlsg$0A^lNlS/|Hy&{/t\SZihUhFv:"pTcϏ%^,fguIϷ*WЛUv}&HQII\;b'$霷$娂" c}\u)#ـچӿiJ.;940ƺbܝD/'t.F<6<ȇ9ɽ0<0/?{I=KgGb07ڠy/[ţu?*ߤE8%'~m8;aW!q5|]:tlZqΐF?Dm U2MYz 67YK!ܲrouPdQm_-ۚ_X@I~[f|e4N'uk]K_ ~$,0vǛ#E4ҿ\w# H>uSoz6ZAwa"DǼs],kE-2=)d9I <0HD*-j9H^ǒ//A`;NQW!4Lym5&L5&XXzU( vzs/&7=6j~/*Hl7wu"<nw( ,Bm5{8Hz>v^4+5WA%#39r,<&9aoyO:nہ_T$>aT.{:!>5oS5Sx֯bu󔹾?Όs~*wQ5=Zٰ~GU?.UT& Wˁ3\υ>1Lj{: ̟UH4mɺ!R#$ݙIWx—"}* g]׾ij{lΉ3峠U,t vo#A\9UUM{܋_5tMN{]9&UU$E!5LtpBi9)9^/ClOQ0 HicYJ@o*<4F<:Sp}H P-`j lU"$@ªR+˼9&An%+5=5:y[:,k(sIA Ezŭ%V^|tzy7~UTbYDEk]h6/BVWe=qInXލ"dPjzmK7e"/DG N֩12B( ^5mr3!{, T&5/J~Y̔y=X76\&4㭀uZ'9b+2_cBRK&Fl*x(Bt~v".ow2#gi[t&1IN*'a߆:K\AI}0@EJ/cFpf5y.RYkr5D<^P,ouŻ}6\Ѭy4ޕêehm E]3ӊSQuLa&\pw!Z &85Zf+Vh(Air%Xcp1 6A~,2?WgKwWk5={F%:ˡ`7>(v^ 4jZUanۍGƗ5.yW@D RX² ^œ8H#; T)JfV"T^ӤMU$c]]'zJ_}$,b(e-ɮw%܉>l{-!RuO>eVϔybAL5QԔ~!g+Io{K0]% w\5?pxʕߤ!lBaǿuJ=άQ]K-%e8&6jڕ9JHWk 깇;>\XrAY^ Ynxڰ),ʫDp gPs+x[anN@ 9هP$8 PeNVwL`&D~v,e#<ԮC// Vրoׁ]xƈ>9P~Ag*19`OCMj?mkR/RMxW8G!_N = f!47/wu.Bdt|NB[‡Aj1=kQ)$]f@r8_aƃQj:i,WEnltӔSOjpU Rm0mKq:%6mkư =Bﭗ|ቖHB63OʍhM:0+j^%uV6t)1ءŜ״PqFIYvu{Oq?SഁL+J)hX ~%O(T xWf$4`iyQL0Ħ$)Ƣ :tR՚=9Aîgv,'ѨIJg4Z'"]0u?X]}`^ $2E39BX{vE1#6ͦ[}jhL/d#Bw1}!`4|vOyAKP1Ν#Kga uJ_ Y!c$+w㉎Z/E V| c+`,0"AA(< ,m^;n?ԗ/AIQb3^ `2mT簖'xFxEst4zc촼p _S5\B>H{C0Ҝ6_;,E!{1{gTVR1/8/u"D2_/t4j{c[W6~tm]3s©'ֶdm( 5ĖC!ta#GOljv7P{G!5Ⱦ47 <'D{6`*В.[b R{m )XNi SxCk_\W$30גm:Ŷ,LT7}'agK~' QZBδ*tɍ) 2LpaRga8+7[4Aky틝eZmKRV1ÓFk4JbgOܗDp>?II u7g(!9Mw$*q"/wm;;$;B<@/Dփճ-wNKaB>(cUŅ荢a{n|ntW7SE+s8Krg|nM+< M<7))_z~g\}\}d_.>ۋt YaN[k(|QLƷ g920[)~Ѩa5~ձu=Mݛ'~k#y9TBDL@`& ?1+n! L*s7,BȭtM_nx!^ dt) ߬HvwF3neϖy%u6*gMZ"!w'd5|^8XC3>aP~gZ֕]>>}UD_B "܅80҄Fkfi3ݟ .S-0hc֓$[ {\;̴ 6Re=1!?|ۋ O(<<ݝvOQf0H7eK |\ 7:pY^>IwJ<4uO^ŵ,5u*QoPgnpM_pnZ*4Hsnj"Ls!T76Nuj'=7ɥ <ſ4:+TlN'Đxhy; ͼm%0ަΛFhC?@+ ]{t?zq,q2 ^h({=ǔJ}U@I- =|m,Odl>~RSPv 3HUACyz K ~pPM `R 64BY r/Amraϗi2_Д&JȋkupӀN_}k27C31jZ/#t憎^iO4q5! ۾qbFH9"m $rӁ,JKYfЇ w ).E6Y0@m" €%5 @t9r@;Ⳡf7x63\!Bx+#j ufo.xN|X4z'bˏ#%T,Zz9PyH?%q!z(N#ql7VFs/EiG 'f_G|,:c3ǰn? +/*;=Fj;L?V(-'Fp#z8awͺj"yJ!FLN>T^ihG tpDb! ~\ ^m7¦@*_*.NL My)KCjE'\  hb?TE>^z֥y=3ɰ\8v9*XS[[jJJTI6R4\rZes*{:0bзֆ|TIy7FsG^8lNlNiqB4OřVv>}Iu9#-PuSjK~C Ӹ8d^\!0 AlybL~ =_(7}52'vj.com> * @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ /** * @ignore */ define('IN_PHPBB', true); $phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './'; $phpEx = substr(strrchr(__FILE__, '.'), 1); include($phpbb_root_path . 'common.' . $phpEx); // Start session management $user->session_begin(); $auth->acl($user->data); $user->setup('search'); // Define initial vars $mode = $request->variable('mode', ''); $search_id = $request->variable('search_id', ''); $start = max($request->variable('start', 0), 0); $post_id = $request->variable('p', 0); $topic_id = $request->variable('t', 0); $view = $request->variable('view', ''); $submit = $request->variable('submit', false); $keywords = $request->variable('keywords', '', true); $add_keywords = $request->variable('add_keywords', '', true); $author = $request->variable('author', '', true); $author_id = $request->variable('author_id', 0); $show_results = ($topic_id) ? 'posts' : $request->variable('sr', 'posts'); $show_results = ($show_results == 'posts') ? 'posts' : 'topics'; $search_terms = $request->variable('terms', 'all'); $search_fields = $request->variable('sf', 'all'); $search_child = $request->variable('sc', true); $sort_days = $request->variable('st', 0); $sort_key = $request->variable('sk', 't'); $sort_dir = $request->variable('sd', 'd'); $return_chars = $request->variable('ch', ($topic_id) ? -1 : 300); $search_forum = $request->variable('fid', array(0)); // We put login boxes for the case if search_id is newposts, egosearch or unreadposts // because a guest should be able to log in even if guests search is not permitted switch ($search_id) { // Egosearch is an author search case 'egosearch': $author_id = $user->data['user_id']; if ($user->data['user_id'] == ANONYMOUS) { login_box('', $user->lang['LOGIN_EXPLAIN_EGOSEARCH']); } break; // Search for unread posts needs to be allowed and user to be logged in if topics tracking for guests is disabled case 'unreadposts': if (!$config['load_unreads_search']) { $template->assign_var('S_NO_SEARCH', true); trigger_error('NO_SEARCH_UNREADS'); } else if (!$config['load_anon_lastread'] && !$user->data['is_registered']) { login_box('', $user->lang['LOGIN_EXPLAIN_UNREADSEARCH']); } break; // The "new posts" search uses user_lastvisit which is user based, so it should require user to log in. case 'newposts': if ($user->data['user_id'] == ANONYMOUS) { login_box('', $user->lang['LOGIN_EXPLAIN_NEWPOSTS']); } break; default: // There's nothing to do here for now ;) break; } // Is user able to search? Has search been disabled? if (!$auth->acl_get('u_search') || !$auth->acl_getf_global('f_search') || !$config['load_search']) { $template->assign_var('S_NO_SEARCH', true); trigger_error('NO_SEARCH'); } // Check search load limit if ($user->load && $config['limit_search_load'] && ($user->load > doubleval($config['limit_search_load']))) { $template->assign_var('S_NO_SEARCH', true); trigger_error('NO_SEARCH_LOAD'); } // It is applicable if the configuration setting is non-zero, and the user cannot // ignore the flood setting, and the search is a keyword search. $interval = ($user->data['user_id'] == ANONYMOUS) ? $config['search_anonymous_interval'] : $config['search_interval']; if ($interval && !in_array($search_id, array('unreadposts', 'unanswered', 'active_topics', 'egosearch')) && !$auth->acl_get('u_ignoreflood')) { if ($user->data['user_last_search'] > time() - $interval) { $template->assign_var('S_NO_SEARCH', true); trigger_error($user->lang('NO_SEARCH_TIME', (int) ($user->data['user_last_search'] + $interval - time()))); } } // Define some vars $limit_days = array(0 => $user->lang['ALL_RESULTS'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); $sort_by_text = array('a' => $user->lang['SORT_AUTHOR'], 't' => $user->lang['SORT_TIME'], 'f' => $user->lang['SORT_FORUM'], 'i' => $user->lang['SORT_TOPIC_TITLE'], 's' => $user->lang['SORT_POST_SUBJECT']); $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = ''; gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param); /* @var $phpbb_content_visibility \phpbb\content_visibility */ $phpbb_content_visibility = $phpbb_container->get('content.visibility'); /* @var $pagination \phpbb\pagination */ $pagination = $phpbb_container->get('pagination'); /** * This event allows you to alter the above parameters, such as keywords and submit * * @event core.search_modify_submit_parameters * @var string keywords The search keywords * @var string author Specifies the author match, when ANONYMOUS is also a search-match * @var int author_id ID of the author to search by * @var string search_id Predefined search type name * @var bool submit Whether or not the form has been submitted * @since 3.1.10-RC1 */ $vars = array( 'keywords', 'author', 'author_id', 'search_id', 'submit', ); extract($phpbb_dispatcher->trigger_event('core.search_modify_submit_parameters', compact($vars))); if ($keywords || $author || $author_id || $search_id || $submit) { // clear arrays $id_ary = array(); // If we are looking for authors get their ids $author_id_ary = array(); $sql_author_match = ''; if ($author_id) { $author_id_ary[] = $author_id; } else if ($author) { if ((strpos($author, '*') !== false) && (utf8_strlen(str_replace(array('*', '%'), '', $author)) < $config['min_search_author_chars'])) { trigger_error($user->lang('TOO_FEW_AUTHOR_CHARS', (int) $config['min_search_author_chars'])); } $sql_where = (strpos($author, '*') !== false) ? ' username_clean ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), utf8_clean_string($author))) : " username_clean = '" . $db->sql_escape(utf8_clean_string($author)) . "'"; $sql = 'SELECT user_id FROM ' . USERS_TABLE . " WHERE $sql_where AND user_type <> " . USER_IGNORE; $result = $db->sql_query_limit($sql, 100); while ($row = $db->sql_fetchrow($result)) { $author_id_ary[] = (int) $row['user_id']; } $db->sql_freeresult($result); $sql_where = (strpos($author, '*') !== false) ? ' post_username ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), utf8_clean_string($author))) : " post_username = '" . $db->sql_escape(utf8_clean_string($author)) . "'"; $sql = 'SELECT 1 as guest_post FROM ' . POSTS_TABLE . " WHERE $sql_where AND poster_id = " . ANONYMOUS; $result = $db->sql_query_limit($sql, 1); $found_guest_post = $db->sql_fetchfield('guest_post'); $db->sql_freeresult($result); if ($found_guest_post) { $author_id_ary[] = ANONYMOUS; $sql_author_match = (strpos($author, '*') !== false) ? ' ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), utf8_clean_string($author))) : " = '" . $db->sql_escape(utf8_clean_string($author)) . "'"; } if (!count($author_id_ary)) { trigger_error('NO_SEARCH_RESULTS'); } } // if we search in an existing search result just add the additional keywords. But we need to use "all search terms"-mode // so we can keep the old keywords in their old mode, but add the new ones as required words if ($add_keywords) { if ($search_terms == 'all') { $keywords .= ' ' . $add_keywords; } else { $search_terms = 'all'; $keywords = implode(' |', explode(' ', preg_replace('#\s+#u', ' ', $keywords))) . ' ' .$add_keywords; } } // Which forums should not be searched? Author searches are also carried out in unindexed forums if (empty($keywords) && count($author_id_ary)) { $ex_fid_ary = array_keys($auth->acl_getf('!f_read', true)); } else { $ex_fid_ary = array_unique(array_merge(array_keys($auth->acl_getf('!f_read', true)), array_keys($auth->acl_getf('!f_search', true)))); } $not_in_fid = (count($ex_fid_ary)) ? 'WHERE ' . $db->sql_in_set('f.forum_id', $ex_fid_ary, true) . " OR (f.forum_password <> '' AND fa.user_id <> " . (int) $user->data['user_id'] . ')' : ""; $sql = 'SELECT f.forum_id, f.forum_name, f.parent_id, f.forum_type, f.right_id, f.forum_password, f.forum_flags, fa.user_id FROM ' . FORUMS_TABLE . ' f LEFT JOIN ' . FORUMS_ACCESS_TABLE . " fa ON (fa.forum_id = f.forum_id AND fa.session_id = '" . $db->sql_escape($user->session_id) . "') $not_in_fid ORDER BY f.left_id"; $result = $db->sql_query($sql); $right_id = 0; $reset_search_forum = true; while ($row = $db->sql_fetchrow($result)) { if ($row['forum_password'] && $row['user_id'] != $user->data['user_id']) { $ex_fid_ary[] = (int) $row['forum_id']; continue; } // Exclude forums from active topics if (!($row['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS) && ($search_id == 'active_topics')) { $ex_fid_ary[] = (int) $row['forum_id']; continue; } if (count($search_forum)) { if ($search_child) { if (in_array($row['forum_id'], $search_forum) && $row['right_id'] > $right_id) { $right_id = (int) $row['right_id']; } else if ($row['right_id'] < $right_id) { continue; } } if (!in_array($row['forum_id'], $search_forum)) { $ex_fid_ary[] = (int) $row['forum_id']; $reset_search_forum = false; } } } $db->sql_freeresult($result); // find out in which forums the user is allowed to view posts $m_approve_posts_fid_sql = $phpbb_content_visibility->get_global_visibility_sql('post', $ex_fid_ary, 'p.'); $m_approve_topics_fid_sql = $phpbb_content_visibility->get_global_visibility_sql('topic', $ex_fid_ary, 't.'); if ($reset_search_forum) { $search_forum = array(); } // Select which method we'll use to obtain the post_id or topic_id information $search_type = $config['search_type']; if (!class_exists($search_type)) { trigger_error('NO_SUCH_SEARCH_MODULE'); } // We do some additional checks in the module to ensure it can actually be utilised $error = false; $search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher); if ($error) { trigger_error($error); } // let the search module split up the keywords if ($keywords) { $correct_query = $search->split_keywords($keywords, $search_terms); $common_words = $search->get_common_words(); if (!$correct_query || (!$search->get_search_query() && !count($author_id_ary) && !$search_id)) { $ignored = (count($common_words)) ? sprintf($user->lang['IGNORED_TERMS_EXPLAIN'], implode(' ', $common_words)) . '<br />' : ''; $word_length = $search->get_word_length(); if ($word_length) { trigger_error($ignored . $user->lang('NO_KEYWORDS', $user->lang('CHARACTERS', (int) $word_length['min']), $user->lang('CHARACTERS', (int) $word_length['max']))); } else { trigger_error($ignored); } } } if (!$keywords && count($author_id_ary)) { // if it is an author search we want to show topics by default $show_results = ($topic_id) ? 'posts' : $request->variable('sr', ($search_id == 'egosearch') ? 'topics' : 'posts'); $show_results = ($show_results == 'posts') ? 'posts' : 'topics'; } // define some variables needed for retrieving post_id/topic_id information $sort_by_sql = array('a' => 'u.username_clean', 't' => (($show_results == 'posts') ? 'p.post_time' : 't.topic_last_post_time'), 'f' => 'f.forum_id', 'i' => 't.topic_title', 's' => (($show_results == 'posts') ? 'p.post_subject' : 't.topic_title')); /** * Event to modify the SQL parameters before pre-made searches * * @event core.search_modify_param_before * @var string keywords String of the specified keywords * @var array sort_by_sql Array of SQL sorting instructions * @var array ex_fid_ary Array of excluded forum ids * @var array author_id_ary Array of exclusive author ids * @var string search_id The id of the search request * @var array id_ary Array of post or topic ids for search result * @var string show_results 'posts' or 'topics' type of ids * @since 3.1.3-RC1 * @changed 3.1.10-RC1 Added id_ary, show_results */ $vars = array( 'keywords', 'sort_by_sql', 'ex_fid_ary', 'author_id_ary', 'search_id', 'id_ary', 'show_results', ); extract($phpbb_dispatcher->trigger_event('core.search_modify_param_before', compact($vars))); // pre-made searches $sql = $field = $l_search_title = ''; if ($search_id) { switch ($search_id) { // Oh holy Bob, bring us some activity... case 'active_topics': $l_search_title = $user->lang['SEARCH_ACTIVE_TOPICS']; $show_results = 'topics'; $sort_key = 't'; $sort_dir = 'd'; $sort_days = $request->variable('st', 7); $sort_by_sql['t'] = 't.topic_last_post_time'; gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param); $s_sort_key = $s_sort_dir = ''; $last_post_time_sql = ($sort_days) ? ' AND t.topic_last_post_time > ' . (time() - ($sort_days * 24 * 3600)) : ''; $sql = 'SELECT t.topic_last_post_time, t.topic_id FROM ' . TOPICS_TABLE . " t WHERE t.topic_moved_id = 0 $last_post_time_sql AND " . $m_approve_topics_fid_sql . ' ' . ((count($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('t.forum_id', $ex_fid_ary, true) : '') . ' ORDER BY t.topic_last_post_time DESC'; $field = 'topic_id'; break; case 'unanswered': $l_search_title = $user->lang['SEARCH_UNANSWERED']; $show_results = $request->variable('sr', 'topics'); $show_results = ($show_results == 'posts') ? 'posts' : 'topics'; $sort_by_sql['t'] = ($show_results == 'posts') ? 'p.post_time' : 't.topic_last_post_time'; $sort_by_sql['s'] = ($show_results == 'posts') ? 'p.post_subject' : 't.topic_title'; $sql_sort = 'ORDER BY ' . $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); $sort_join = ($sort_key == 'f') ? FORUMS_TABLE . ' f, ' : ''; $sql_sort = ($sort_key == 'f') ? ' AND f.forum_id = p.forum_id ' . $sql_sort : $sql_sort; if ($sort_days) { $last_post_time = 'AND p.post_time > ' . (time() - ($sort_days * 24 * 3600)); } else { $last_post_time = ''; } if ($sort_key == 'a') { $sort_join = USERS_TABLE . ' u, '; $sql_sort = ' AND u.user_id = p.poster_id ' . $sql_sort; } if ($show_results == 'posts') { $sql = "SELECT p.post_id FROM $sort_join" . POSTS_TABLE . ' p, ' . TOPICS_TABLE . " t WHERE t.topic_posts_approved = 1 AND p.topic_id = t.topic_id $last_post_time AND $m_approve_posts_fid_sql " . ((count($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '') . " $sql_sort"; $field = 'post_id'; } else { $sql = 'SELECT DISTINCT ' . $sort_by_sql[$sort_key] . ", p.topic_id FROM $sort_join" . POSTS_TABLE . ' p, ' . TOPICS_TABLE . " t WHERE t.topic_posts_approved = 1 AND t.topic_moved_id = 0 AND p.topic_id = t.topic_id $last_post_time AND $m_approve_topics_fid_sql " . ((count($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '') . " $sql_sort"; $field = 'topic_id'; } break; case 'unreadposts': $l_search_title = $user->lang['SEARCH_UNREAD']; // force sorting $show_results = 'topics'; $sort_key = 't'; $sort_by_sql['t'] = 't.topic_last_post_time'; $sql_sort = 'ORDER BY ' . $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); $sql_where = 'AND t.topic_moved_id = 0 AND ' . $m_approve_topics_fid_sql . ' ' . ((count($ex_fid_ary)) ? 'AND ' . $db->sql_in_set('t.forum_id', $ex_fid_ary, true) : ''); gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param); $s_sort_key = $s_sort_dir = $u_sort_param = $s_limit_days = ''; $template->assign_var('U_MARK_ALL_READ', ($user->data['is_registered'] || $config['load_anon_lastread']) ? append_sid("{$phpbb_root_path}index.$phpEx", 'hash=' . generate_link_hash('global') . '&amp;mark=forums&amp;mark_time=' . time()) : ''); break; case 'newposts': $l_search_title = $user->lang['SEARCH_NEW']; // force sorting $show_results = ($request->variable('sr', 'topics') == 'posts') ? 'posts' : 'topics'; $sort_key = 't'; $sort_dir = 'd'; $sort_by_sql['t'] = ($show_results == 'posts') ? 'p.post_time' : 't.topic_last_post_time'; $sql_sort = 'ORDER BY ' . $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param); $s_sort_key = $s_sort_dir = $u_sort_param = $s_limit_days = ''; if ($show_results == 'posts') { $sql = 'SELECT p.post_id FROM ' . POSTS_TABLE . ' p WHERE p.post_time > ' . $user->data['user_lastvisit'] . ' AND ' . $m_approve_posts_fid_sql . ' ' . ((count($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '') . " $sql_sort"; $field = 'post_id'; } else { $sql = 'SELECT t.topic_id FROM ' . TOPICS_TABLE . ' t WHERE t.topic_last_post_time > ' . $user->data['user_lastvisit'] . ' AND t.topic_moved_id = 0 AND ' . $m_approve_topics_fid_sql . ' ' . ((count($ex_fid_ary)) ? 'AND ' . $db->sql_in_set('t.forum_id', $ex_fid_ary, true) : '') . " $sql_sort"; /* [Fix] queued replies missing from "view new posts" (Bug #42705 - Patch by Paul) - Creates temporary table, query is far from optimized $sql = 'SELECT t.topic_id FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . ' p WHERE p.post_time > ' . $user->data['user_lastvisit'] . ' AND t.topic_id = p.topic_id AND t.topic_moved_id = 0 AND ' . $m_approve_topics_fid_sql . " GROUP BY t.topic_id $sql_sort"; */ $field = 'topic_id'; } break; case 'egosearch': $l_search_title = $user->lang['SEARCH_SELF']; break; } } /** * Event to modify data after pre-made searches * * @event core.search_modify_param_after * @var string l_search_title The title of the search page * @var string search_id Predefined search type name * @var string show_results Display topics or posts * @var string sql SQL query corresponding to the pre-made search id * @since 3.1.7-RC1 */ $vars = array( 'l_search_title', 'search_id', 'show_results', 'sql', ); extract($phpbb_dispatcher->trigger_event('core.search_modify_param_after', compact($vars))); // show_results should not change after this $per_page = ($show_results == 'posts') ? $config['posts_per_page'] : $config['topics_per_page']; $total_match_count = 0; // Set limit for the $total_match_count to reduce server load $total_matches_limit = 1000; $found_more_search_matches = false; if ($search_id) { if ($sql) { // Only return up to $total_matches_limit+1 ids (the last one will be removed later) $result = $db->sql_query_limit($sql, $total_matches_limit + 1); while ($row = $db->sql_fetchrow($result)) { $id_ary[] = (int) $row[$field]; } $db->sql_freeresult($result); } else if ($search_id == 'unreadposts') { // Only return up to $total_matches_limit+1 ids (the last one will be removed later) $id_ary = array_keys(get_unread_topics($user->data['user_id'], $sql_where, $sql_sort, $total_matches_limit + 1)); } else { $search_id = ''; } $total_match_count = count($id_ary); if ($total_match_count) { // Limit the number to $total_matches_limit for pre-made searches if ($total_match_count > $total_matches_limit) { $found_more_search_matches = true; $total_match_count = $total_matches_limit; } // Make sure $start is set to the last page if it exceeds the amount $start = $pagination->validate_start($start, $per_page, $total_match_count); $id_ary = array_slice($id_ary, $start, $per_page); } else { // Set $start to 0 if no matches were found $start = 0; } } // make sure that some arrays are always in the same order sort($ex_fid_ary); sort($author_id_ary); if ($search->get_search_query()) { $total_match_count = $search->keyword_search($show_results, $search_fields, $search_terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_posts_fid_sql, $topic_id, $author_id_ary, $sql_author_match, $id_ary, $start, $per_page); } else if (count($author_id_ary)) { $firstpost_only = ($search_fields === 'firstpost' || $search_fields == 'titleonly') ? true : false; $total_match_count = $search->author_search($show_results, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_posts_fid_sql, $topic_id, $author_id_ary, $sql_author_match, $id_ary, $start, $per_page); } /** * Event to search otherwise than by keywords or author * * @event core.search_backend_search_after * @var string show_results 'posts' or 'topics' type of ids * @var string search_fields The data fields to search in * @var string search_terms Is either 'all' (use query as entered, words without prefix should default to "have to be in field") or 'any' (ignore search query parts and just return all posts that contain any of the specified words) * @var array sort_by_sql Array of SQL sorting instructions * @var string sort_key The sort key * @var string sort_dir The sort direction * @var int sort_days Limit the age of results * @var array ex_fid_ary Array of excluded forum ids * @var string m_approve_posts_fid_sql Specifies which types of posts the user can view in which forums * @var int topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched * @var array author_id_ary Array of exclusive author ids * @var string sql_author_match Specifies the author match, when ANONYMOUS is also a search-match * @var array id_ary Array of post or topic ids for search result * @var int start The starting id of the results * @var int per_page Number of ids each page is supposed to contain * @var int total_match_count The total number of search matches * @since 3.1.10-RC1 */ $vars = array( 'show_results', 'search_fields', 'search_terms', 'sort_by_sql', 'sort_key', 'sort_dir', 'sort_days', 'ex_fid_ary', 'm_approve_posts_fid_sql', 'topic_id', 'author_id_ary', 'sql_author_match', 'id_ary', 'start', 'per_page', 'total_match_count', ); extract($phpbb_dispatcher->trigger_event('core.search_backend_search_after', compact($vars))); $sql_where = ''; if (count($id_ary)) { $sql_where .= $db->sql_in_set(($show_results == 'posts') ? 'p.post_id' : 't.topic_id', $id_ary); $sql_where .= (count($ex_fid_ary)) ? ' AND (' . $db->sql_in_set('f.forum_id', $ex_fid_ary, true) . ' OR f.forum_id IS NULL)' : ''; $sql_where .= ' AND ' . (($show_results == 'posts') ? $m_approve_posts_fid_sql : $m_approve_topics_fid_sql); } if ($show_results == 'posts') { include($phpbb_root_path . 'includes/functions_posting.' . $phpEx); } else { include($phpbb_root_path . 'includes/functions_display.' . $phpEx); } $user->add_lang('viewtopic'); // Grab icons $icons = $cache->obtain_icons(); // define some vars for urls // A single wildcard will make the search results look ugly $hilit = phpbb_clean_search_string(str_replace(array('+', '-', '|', '(', ')', '&quot;'), ' ', $keywords)); $hilit = str_replace(' ', '|', $hilit); $u_hilit = urlencode(htmlspecialchars_decode(str_replace('|', ' ', $hilit))); $u_show_results = '&amp;sr=' . $show_results; $u_search_forum = implode('&amp;fid%5B%5D=', $search_forum); $u_search = append_sid("{$phpbb_root_path}search.$phpEx", $u_sort_param . $u_show_results); $u_search .= ($search_id) ? '&amp;search_id=' . $search_id : ''; $u_search .= ($u_hilit) ? '&amp;keywords=' . urlencode(htmlspecialchars_decode($keywords)) : ''; $u_search .= ($search_terms != 'all') ? '&amp;terms=' . $search_terms : ''; $u_search .= ($topic_id) ? '&amp;t=' . $topic_id : ''; $u_search .= ($author) ? '&amp;author=' . urlencode(htmlspecialchars_decode($author)) : ''; $u_search .= ($author_id) ? '&amp;author_id=' . $author_id : ''; $u_search .= ($u_search_forum) ? '&amp;fid%5B%5D=' . $u_search_forum : ''; $u_search .= (!$search_child) ? '&amp;sc=0' : ''; $u_search .= ($search_fields != 'all') ? '&amp;sf=' . $search_fields : ''; $u_search .= ($return_chars != 300) ? '&amp;ch=' . $return_chars : ''; /** * Event to add or modify search URL parameters * * @event core.search_modify_url_parameters * @var string u_search Search URL parameters string * @var string search_id Predefined search type name * @var string show_results String indicating the show results mode * @var string sql_where The SQL WHERE string used by search to get topic data * @var int total_match_count The total number of search matches * @var array ex_fid_ary Array of excluded forum ids * @since 3.1.7-RC1 * @changed 3.1.10-RC1 Added show_results, sql_where, total_match_count * @changed 3.1.11-RC1 Added ex_fid_ary */ $vars = array( 'u_search', 'search_id', 'show_results', 'sql_where', 'total_match_count', 'ex_fid_ary', ); extract($phpbb_dispatcher->trigger_event('core.search_modify_url_parameters', compact($vars))); if ($sql_where) { if ($show_results == 'posts') { // @todo Joining this query to the one below? $sql = 'SELECT zebra_id, friend, foe FROM ' . ZEBRA_TABLE . ' WHERE user_id = ' . $user->data['user_id']; $result = $db->sql_query($sql); $zebra = array(); while ($row = $db->sql_fetchrow($result)) { $zebra[($row['friend']) ? 'friend' : 'foe'][] = $row['zebra_id']; } $db->sql_freeresult($result); $sql_array = array( 'SELECT' => 'p.*, f.forum_id, f.forum_name, t.*, u.username, u.username_clean, u.user_sig, u.user_sig_bbcode_uid, u.user_colour', 'FROM' => array( POSTS_TABLE => 'p', ), 'LEFT_JOIN' => array( array( 'FROM' => array(TOPICS_TABLE => 't'), 'ON' => 'p.topic_id = t.topic_id', ), array( 'FROM' => array(FORUMS_TABLE => 'f'), 'ON' => 'p.forum_id = f.forum_id', ), array( 'FROM' => array(USERS_TABLE => 'u'), 'ON' => 'p.poster_id = u.user_id', ), ), 'WHERE' => $sql_where, 'ORDER_BY' => $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC'), ); /** * Event to modify the SQL query before the posts data is retrieved * * @event core.search_get_posts_data * @var array sql_array The SQL array * @var array zebra Array of zebra data for the current user * @var int total_match_count The total number of search matches * @var string keywords String of the specified keywords * @var array sort_by_sql Array of SQL sorting instructions * @var string s_sort_dir The sort direction * @var string s_sort_key The sort key * @var string s_limit_days Limit the age of results * @var array ex_fid_ary Array of excluded forum ids * @var array author_id_ary Array of exclusive author ids * @var string search_fields The data fields to search in * @var int search_id The id of the search request * @var int start The starting id of the results * @since 3.1.0-b3 */ $vars = array( 'sql_array', 'zebra', 'total_match_count', 'keywords', 'sort_by_sql', 's_sort_dir', 's_sort_key', 's_limit_days', 'ex_fid_ary', 'author_id_ary', 'search_fields', 'search_id', 'start', ); extract($phpbb_dispatcher->trigger_event('core.search_get_posts_data', compact($vars))); $sql = $db->sql_build_query('SELECT', $sql_array); } else { $sql_from = TOPICS_TABLE . ' t LEFT JOIN ' . FORUMS_TABLE . ' f ON (f.forum_id = t.forum_id) ' . (($sort_key == 'a') ? ' LEFT JOIN ' . USERS_TABLE . ' u ON (u.user_id = t.topic_poster) ' : ''); $sql_select = 't.*, f.forum_id, f.forum_name'; if ($user->data['is_registered']) { if ($config['load_db_track'] && $author_id !== $user->data['user_id']) { $sql_from .= ' LEFT JOIN ' . TOPICS_POSTED_TABLE . ' tp ON (tp.user_id = ' . $user->data['user_id'] . ' AND t.topic_id = tp.topic_id)'; $sql_select .= ', tp.topic_posted'; } if ($config['load_db_lastread']) { $sql_from .= ' LEFT JOIN ' . TOPICS_TRACK_TABLE . ' tt ON (tt.user_id = ' . $user->data['user_id'] . ' AND t.topic_id = tt.topic_id) LEFT JOIN ' . FORUMS_TRACK_TABLE . ' ft ON (ft.user_id = ' . $user->data['user_id'] . ' AND ft.forum_id = f.forum_id)'; $sql_select .= ', tt.mark_time, ft.mark_time as f_mark_time'; } } if ($config['load_anon_lastread'] || ($user->data['is_registered'] && !$config['load_db_lastread'])) { $tracking_topics = $request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE); $tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array(); } $sql_order_by = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC'); /** * Event to modify the SQL query before the topic data is retrieved * * @event core.search_get_topic_data * @var string sql_select The SQL SELECT string used by search to get topic data * @var string sql_from The SQL FROM string used by search to get topic data * @var string sql_where The SQL WHERE string used by search to get topic data * @var int total_match_count The total number of search matches * @var array sort_by_sql Array of SQL sorting instructions * @var string sort_dir The sorting direction * @var string sort_key The sorting key * @var string sql_order_by The SQL ORDER BY string used by search to get topic data * @since 3.1.0-a1 * @changed 3.1.0-RC5 Added total_match_count * @changed 3.1.7-RC1 Added sort_by_sql, sort_dir, sort_key, sql_order_by */ $vars = array( 'sql_select', 'sql_from', 'sql_where', 'total_match_count', 'sort_by_sql', 'sort_dir', 'sort_key', 'sql_order_by', ); extract($phpbb_dispatcher->trigger_event('core.search_get_topic_data', compact($vars))); $sql = "SELECT $sql_select FROM $sql_from WHERE $sql_where ORDER BY $sql_order_by"; } $result = $db->sql_query($sql); $result_topic_id = 0; $rowset = $attachments = $topic_tracking_info = array(); if ($show_results == 'topics') { $forums = $rowset = $shadow_topic_list = array(); while ($row = $db->sql_fetchrow($result)) { $row['forum_id'] = (int) $row['forum_id']; $row['topic_id'] = (int) $row['topic_id']; if ($row['topic_status'] == ITEM_MOVED) { $shadow_topic_list[$row['topic_moved_id']] = $row['topic_id']; } $rowset[$row['topic_id']] = $row; if (!isset($forums[$row['forum_id']]) && $user->data['is_registered'] && $config['load_db_lastread']) { $forums[$row['forum_id']]['mark_time'] = $row['f_mark_time']; } $forums[$row['forum_id']]['topic_list'][] = $row['topic_id']; $forums[$row['forum_id']]['rowset'][$row['topic_id']] = &$rowset[$row['topic_id']]; } $db->sql_freeresult($result); // If we have some shadow topics, update the rowset to reflect their topic information if (count($shadow_topic_list)) { $sql = 'SELECT * FROM ' . TOPICS_TABLE . ' WHERE ' . $db->sql_in_set('topic_id', array_keys($shadow_topic_list)); $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) { $orig_topic_id = $shadow_topic_list[$row['topic_id']]; // We want to retain some values $row = array_merge($row, array( 'topic_moved_id' => $rowset[$orig_topic_id]['topic_moved_id'], 'topic_status' => $rowset[$orig_topic_id]['topic_status'], 'forum_name' => $rowset[$orig_topic_id]['forum_name']) ); $rowset[$orig_topic_id] = $row; } $db->sql_freeresult($result); } unset($shadow_topic_list); foreach ($forums as $forum_id => $forum) { if ($user->data['is_registered'] && $config['load_db_lastread']) { $topic_tracking_info[$forum_id] = get_topic_tracking($forum_id, $forum['topic_list'], $forum['rowset'], array($forum_id => $forum['mark_time'])); } else if ($config['load_anon_lastread'] || $user->data['is_registered']) { $topic_tracking_info[$forum_id] = get_complete_topic_tracking($forum_id, $forum['topic_list']); if (!$user->data['is_registered']) { $user->data['user_lastmark'] = (isset($tracking_topics['l'])) ? (int) (base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate']) : 0; } } } unset($forums); } else { $text_only_message = ''; $attach_list = array(); while ($row = $db->sql_fetchrow($result)) { /** * Modify the row of a post result before the post_text is trimmed * * @event core.search_modify_post_row * @var string hilit String to highlight * @var array row Array with the post data * @var string u_hilit Highlight string to be injected into URL * @var string view Search results view mode * @var array zebra Array with zebra data for the current user * @since 3.2.2-RC1 */ $vars = array( 'hilit', 'row', 'u_hilit', 'view', 'zebra', ); extract($phpbb_dispatcher->trigger_event('core.search_modify_post_row', compact($vars))); // We pre-process some variables here for later usage $row['post_text'] = censor_text($row['post_text']); $text_only_message = $row['post_text']; // make list items visible as such if ($row['bbcode_uid']) { $text_only_message = str_replace('[*:' . $row['bbcode_uid'] . ']', '&sdot;&nbsp;', $text_only_message); // no BBCode in text only message strip_bbcode($text_only_message, $row['bbcode_uid']); } if ($return_chars == -1 || utf8_strlen($text_only_message) < ($return_chars + 3)) { $row['display_text_only'] = false; // Does this post have an attachment? If so, add it to the list if ($row['post_attachment'] && $config['allow_attachments']) { $attach_list[$row['forum_id']][] = $row['post_id']; } } else { $row['post_text'] = $text_only_message; $row['display_text_only'] = true; } $rowset[] = $row; } $db->sql_freeresult($result); unset($text_only_message); // Pull attachment data if (count($attach_list)) { $use_attach_list = $attach_list; $attach_list = array(); foreach ($use_attach_list as $forum_id => $_list) { if ($auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id)) { $attach_list = array_merge($attach_list, $_list); } } } if (count($attach_list)) { $sql = 'SELECT * FROM ' . ATTACHMENTS_TABLE . ' WHERE ' . $db->sql_in_set('post_msg_id', $attach_list) . ' AND in_message = 0 ORDER BY filetime DESC, post_msg_id ASC'; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) { $attachments[$row['post_msg_id']][] = $row; } $db->sql_freeresult($result); } } if ($hilit) { // Remove bad highlights $hilit_array = array_filter(explode('|', $hilit), 'strlen'); foreach ($hilit_array as $key => $value) { $hilit_array[$key] = phpbb_clean_search_string($value); $hilit_array[$key] = str_replace('\*', '\w*?', preg_quote($hilit_array[$key], '#')); $hilit_array[$key] = preg_replace('#(^|\s)\\\\w\*\?(\s|$)#', '$1\w+?$2', $hilit_array[$key]); } $hilit = implode('|', $hilit_array); } /** * Modify the rowset data * * @event core.search_modify_rowset * @var array attachments Array with posts attachments data * @var string hilit String to highlight * @var array rowset Array with the search results data * @var string show_results String indicating the show results mode * @var array topic_tracking_info Array with the topics tracking data * @var string u_hilit Highlight string to be injected into URL * @var string view Search results view mode * @var array zebra Array with zebra data for the current user * @since 3.1.0-b4 * @changed 3.1.0-b5 Added var show_results */ $vars = array( 'attachments', 'hilit', 'rowset', 'show_results', 'topic_tracking_info', 'u_hilit', 'view', 'zebra', ); extract($phpbb_dispatcher->trigger_event('core.search_modify_rowset', compact($vars))); foreach ($rowset as $row) { $forum_id = $row['forum_id']; $result_topic_id = $row['topic_id']; $topic_title = censor_text($row['topic_title']); $replies = $phpbb_content_visibility->get_count('topic_posts', $row, $forum_id) - 1; $view_topic_url_params = "f=$forum_id&amp;t=$result_topic_id" . (($u_hilit) ? "&amp;hilit=$u_hilit" : ''); $view_topic_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params); if ($show_results == 'topics') { if ($config['load_db_track'] && $author_id === $user->data['user_id']) { $row['topic_posted'] = 1; } $folder_img = $folder_alt = $topic_type = ''; topic_status($row, $replies, (isset($topic_tracking_info[$forum_id][$row['topic_id']]) && $row['topic_last_post_time'] > $topic_tracking_info[$forum_id][$row['topic_id']]) ? true : false, $folder_img, $folder_alt, $topic_type); $unread_topic = (isset($topic_tracking_info[$forum_id][$row['topic_id']]) && $row['topic_last_post_time'] > $topic_tracking_info[$forum_id][$row['topic_id']]) ? true : false; $topic_unapproved = (($row['topic_visibility'] == ITEM_UNAPPROVED || $row['topic_visibility'] == ITEM_REAPPROVE) && $auth->acl_get('m_approve', $forum_id)) ? true : false; $posts_unapproved = ($row['topic_visibility'] == ITEM_APPROVED && $row['topic_posts_unapproved'] && $auth->acl_get('m_approve', $forum_id)) ? true : false; $topic_deleted = $row['topic_visibility'] == ITEM_DELETED; $u_mcp_queue = ($topic_unapproved || $posts_unapproved) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&amp;mode=' . (($topic_unapproved) ? 'approve_details' : 'unapproved_posts') . "&amp;t=$result_topic_id", true, $user->session_id) : ''; $u_mcp_queue = (!$u_mcp_queue && $topic_deleted) ? append_sid("{$phpbb_root_path}mcp.$phpEx", "i=queue&amp;mode=deleted_topics&amp;t=$result_topic_id", true, $user->session_id) : $u_mcp_queue; $row['topic_title'] = preg_replace('#(?!<.*)(?<!\w)(' . $hilit . ')(?!\w|[^<>]*(?:</s(?:cript|tyle))?>)#isu', '<span class="posthilit">$1</span>', $row['topic_title']); $tpl_ary = array( 'TOPIC_AUTHOR' => get_username_string('username', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']), 'TOPIC_AUTHOR_COLOUR' => get_username_string('colour', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']), 'TOPIC_AUTHOR_FULL' => get_username_string('full', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']), 'FIRST_POST_TIME' => $user->format_date($row['topic_time']), 'FIRST_POST_TIME_RFC3339' => gmdate(DATE_RFC3339, $row['topic_time']), 'LAST_POST_SUBJECT' => $row['topic_last_post_subject'], 'LAST_POST_TIME' => $user->format_date($row['topic_last_post_time']), 'LAST_POST_TIME_RFC3339' => gmdate(DATE_RFC3339, $row['topic_last_post_time']), 'LAST_VIEW_TIME' => $user->format_date($row['topic_last_view_time']), 'LAST_VIEW_TIME_RFC3339' => gmdate(DATE_RFC3339, $row['topic_last_view_time']), 'LAST_POST_AUTHOR' => get_username_string('username', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']), 'LAST_POST_AUTHOR_COLOUR' => get_username_string('colour', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']), 'LAST_POST_AUTHOR_FULL' => get_username_string('full', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']), 'TOPIC_TYPE' => $topic_type, 'TOPIC_IMG_STYLE' => $folder_img, 'TOPIC_FOLDER_IMG' => $user->img($folder_img, $folder_alt), 'TOPIC_FOLDER_IMG_ALT' => $user->lang[$folder_alt], 'TOPIC_ICON_IMG' => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['img'] : '', 'TOPIC_ICON_IMG_WIDTH' => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['width'] : '', 'TOPIC_ICON_IMG_HEIGHT' => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['height'] : '', 'ATTACH_ICON_IMG' => ($auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id) && $row['topic_attachment']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '', 'UNAPPROVED_IMG' => ($topic_unapproved || $posts_unapproved) ? $user->img('icon_topic_unapproved', ($topic_unapproved) ? 'TOPIC_UNAPPROVED' : 'POSTS_UNAPPROVED') : '', 'S_TOPIC_TYPE' => $row['topic_type'], 'S_USER_POSTED' => (!empty($row['topic_posted'])) ? true : false, 'S_UNREAD_TOPIC' => $unread_topic, 'S_TOPIC_REPORTED' => (!empty($row['topic_reported']) && $auth->acl_get('m_report', $forum_id)) ? true : false, 'S_TOPIC_UNAPPROVED' => $topic_unapproved, 'S_POSTS_UNAPPROVED' => $posts_unapproved, 'S_TOPIC_DELETED' => $topic_deleted, 'S_HAS_POLL' => ($row['poll_start']) ? true : false, 'U_LAST_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params . '&amp;p=' . $row['topic_last_post_id']) . '#p' . $row['topic_last_post_id'], 'U_LAST_POST_AUTHOR' => get_username_string('profile', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']), 'U_TOPIC_AUTHOR' => get_username_string('profile', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']), 'U_NEWEST_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params . '&amp;view=unread') . '#unread', 'U_MCP_REPORT' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=reports&amp;mode=reports&amp;t=' . $result_topic_id, true, $user->session_id), 'U_MCP_QUEUE' => $u_mcp_queue, ); } else { if ((isset($zebra['foe']) && in_array($row['poster_id'], $zebra['foe'])) && (!$view || $view != 'show' || $post_id != $row['post_id'])) { $template->assign_block_vars('searchresults', array( 'S_IGNORE_POST' => true, 'L_IGNORE_POST' => sprintf($user->lang['POST_BY_FOE'], $row['username'], "<a href=\"$u_search&amp;start=$start&amp;p=" . $row['post_id'] . '&amp;view=show#p' . $row['post_id'] . '">', '</a>')) ); continue; } // Replace naughty words such as farty pants $row['post_subject'] = censor_text($row['post_subject']); if ($row['display_text_only']) { // now find context for the searched words $row['post_text'] = get_context($row['post_text'], array_filter(explode('|', $hilit), 'strlen'), $return_chars); $row['post_text'] = bbcode_nl2br($row['post_text']); } else { $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES; $row['post_text'] = generate_text_for_display($row['post_text'], $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, false); if (!empty($attachments[$row['post_id']])) { parse_attachments($forum_id, $row['post_text'], $attachments[$row['post_id']], $update_count); // we only display inline attachments unset($attachments[$row['post_id']]); } } if ($hilit) { // post highlighting $row['post_text'] = preg_replace('#(?!<.*)(?<!\w)(' . $hilit . ')(?!\w|[^<>]*(?:</s(?:cript|tyle))?>)#isu', '<span class="posthilit">$1</span>', $row['post_text']); $row['post_subject'] = preg_replace('#(?!<.*)(?<!\w)(' . $hilit . ')(?!\w|[^<>]*(?:</s(?:cript|tyle))?>)#isu', '<span class="posthilit">$1</span>', $row['post_subject']); } $tpl_ary = array( 'POST_AUTHOR_FULL' => get_username_string('full', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']), 'POST_AUTHOR_COLOUR' => get_username_string('colour', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']), 'POST_AUTHOR' => get_username_string('username', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']), 'U_POST_AUTHOR' => get_username_string('profile', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']), 'POST_SUBJECT' => $row['post_subject'], 'POST_DATE' => (!empty($row['post_time'])) ? $user->format_date($row['post_time']) : '', 'MESSAGE' => $row['post_text'] ); } $tpl_ary = array_merge($tpl_ary, array( 'FORUM_ID' => $forum_id, 'TOPIC_ID' => $result_topic_id, 'POST_ID' => ($show_results == 'posts') ? $row['post_id'] : false, 'FORUM_TITLE' => $row['forum_name'], 'TOPIC_TITLE' => $topic_title, 'TOPIC_REPLIES' => $replies, 'TOPIC_VIEWS' => $row['topic_views'], 'U_VIEW_TOPIC' => $view_topic_url, 'U_VIEW_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id), 'U_VIEW_POST' => (!empty($row['post_id'])) ? append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=" . $row['topic_id'] . '&amp;p=' . $row['post_id'] . (($u_hilit) ? '&amp;hilit=' . $u_hilit : '')) . '#p' . $row['post_id'] : '', )); /** * Modify the topic data before it is assigned to the template * * @event core.search_modify_tpl_ary * @var array row Array with topic data * @var array tpl_ary Template block array with topic data * @var string show_results Display topics or posts * @var string topic_title Cleaned topic title * @var int replies The number of topic replies * @var string view_topic_url The URL to the topic * @var string folder_img The folder image of the topic * @var string folder_alt The alt attribute of the topic folder img * @var int topic_type The topic type * @var bool unread_topic Whether the topic has unread posts * @var bool topic_unapproved Whether the topic is unapproved * @var int posts_unapproved The number of unapproved posts * @var bool topic_deleted Whether the topic has been deleted * @var string u_mcp_queue The URL to the corresponding MCP queue page * @var array zebra The zebra data of the current user * @var array attachments All the attachments of the search results * @since 3.1.0-a1 * @changed 3.1.0-b3 Added vars show_results, topic_title, replies, * view_topic_url, folder_img, folder_alt, topic_type, unread_topic, * topic_unapproved, posts_unapproved, topic_deleted, u_mcp_queue, * zebra, attachments */ $vars = array( 'row', 'tpl_ary', 'show_results', 'topic_title', 'replies', 'view_topic_url', 'folder_img', 'folder_alt', 'topic_type', 'unread_topic', 'topic_unapproved', 'posts_unapproved', 'topic_deleted', 'u_mcp_queue', 'zebra', 'attachments', ); extract($phpbb_dispatcher->trigger_event('core.search_modify_tpl_ary', compact($vars))); $template->assign_block_vars('searchresults', $tpl_ary); if ($show_results == 'topics') { $pagination->generate_template_pagination($view_topic_url, 'searchresults.pagination', 'start', $replies + 1, $config['posts_per_page'], 1, true, true); } } if ($topic_id && ($topic_id == $result_topic_id)) { $template->assign_vars(array( 'SEARCH_TOPIC' => $topic_title, 'L_RETURN_TO_TOPIC' => $user->lang('RETURN_TO', $topic_title), 'U_SEARCH_TOPIC' => $view_topic_url )); } } unset($rowset); // Output header if ($found_more_search_matches) { $l_search_matches = $user->lang('FOUND_MORE_SEARCH_MATCHES', (int) $total_match_count); } else { $l_search_matches = $user->lang('FOUND_SEARCH_MATCHES', (int) $total_match_count); } // Check if search backend supports phrase search or not $phrase_search_disabled = ''; if (strpos(html_entity_decode($keywords), '"') !== false && method_exists($search, 'supports_phrase_search')) { $phrase_search_disabled = $search->supports_phrase_search() ? false : true; } $pagination->generate_template_pagination($u_search, 'pagination', 'start', $total_match_count, $per_page, $start); $template->assign_vars(array( 'SEARCH_TITLE' => $l_search_title, 'SEARCH_MATCHES' => $l_search_matches, 'SEARCH_WORDS' => $keywords, 'SEARCHED_QUERY' => $search->get_search_query(), 'IGNORED_WORDS' => (!empty($common_words)) ? implode(' ', $common_words) : '', 'PHRASE_SEARCH_DISABLED' => $phrase_search_disabled, 'TOTAL_MATCHES' => $total_match_count, 'SEARCH_IN_RESULTS' => ($search_id) ? false : true, 'S_SELECT_SORT_DIR' => $s_sort_dir, 'S_SELECT_SORT_KEY' => $s_sort_key, 'S_SELECT_SORT_DAYS' => $s_limit_days, 'S_SEARCH_ACTION' => $u_search, 'S_SHOW_TOPICS' => ($show_results == 'posts') ? false : true, 'GOTO_PAGE_IMG' => $user->img('icon_post_target', 'GOTO_PAGE'), 'NEWEST_POST_IMG' => $user->img('icon_topic_newest', 'VIEW_NEWEST_POST'), 'REPORTED_IMG' => $user->img('icon_topic_reported', 'TOPIC_REPORTED'), 'UNAPPROVED_IMG' => $user->img('icon_topic_unapproved', 'TOPIC_UNAPPROVED'), 'DELETED_IMG' => $user->img('icon_topic_deleted', 'TOPIC_DELETED'), 'POLL_IMG' => $user->img('icon_topic_poll', 'TOPIC_POLL'), 'LAST_POST_IMG' => $user->img('icon_topic_latest', 'VIEW_LATEST_POST'), 'U_SEARCH_WORDS' => $u_search, )); /** * Modify the title and/or load data for the search results page * * @event core.search_results_modify_search_title * @var int author_id ID of the author to search by * @var string l_search_title The title of the search page * @var string search_id Predefined search type name * @var string show_results Search results output mode - topics or posts * @var int start The starting id of the results * @var int total_match_count The count of search results * @var string keywords The search keywords * @since 3.1.0-RC4 * @changed 3.1.6-RC1 Added total_match_count and keywords */ $vars = array( 'author_id', 'l_search_title', 'search_id', 'show_results', 'start', 'total_match_count', 'keywords', ); extract($phpbb_dispatcher->trigger_event('core.search_results_modify_search_title', compact($vars))); page_header(($l_search_title) ? $l_search_title : $user->lang['SEARCH']); $template->set_filenames(array( 'body' => 'search_results.html') ); make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx")); page_footer(); } // Search forum $rowset = array(); $s_forums = ''; $sql = 'SELECT f.forum_id, f.forum_name, f.parent_id, f.forum_type, f.left_id, f.right_id, f.forum_password, f.enable_indexing, fa.user_id FROM ' . FORUMS_TABLE . ' f LEFT JOIN ' . FORUMS_ACCESS_TABLE . " fa ON (fa.forum_id = f.forum_id AND fa.session_id = '" . $db->sql_escape($user->session_id) . "') ORDER BY f.left_id ASC"; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) { $rowset[(int) $row['forum_id']] = $row; } $db->sql_freeresult($result); $right = $cat_right = $padding_inc = 0; $padding = $forum_list = $holding = ''; $pad_store = array('0' => ''); /** * Modify the forum select list for advanced search page * * @event core.search_modify_forum_select_list * @var array rowset Array with the forums list data * @since 3.1.10-RC1 */ $vars = array('rowset'); extract($phpbb_dispatcher->trigger_event('core.search_modify_forum_select_list', compact($vars))); foreach ($rowset as $row) { if ($row['forum_type'] == FORUM_CAT && ($row['left_id'] + 1 == $row['right_id'])) { // Non-postable forum with no subforums, don't display continue; } if ($row['forum_type'] == FORUM_POST && ($row['left_id'] + 1 == $row['right_id']) && !$row['enable_indexing']) { // Postable forum with no subforums and indexing disabled, don't display continue; } if ($row['forum_type'] == FORUM_LINK || ($row['forum_password'] && !$row['user_id'])) { // if this forum is a link or password protected (user has not entered the password yet) then skip to the next branch continue; } if ($row['left_id'] < $right) { $padding .= '&nbsp; &nbsp;'; $pad_store[$row['parent_id']] = $padding; } else if ($row['left_id'] > $right + 1) { if (isset($pad_store[$row['parent_id']])) { $padding = $pad_store[$row['parent_id']]; } else { continue; } } $right = $row['right_id']; if ($auth->acl_gets('!f_search', '!f_list', $row['forum_id'])) { // if the user does not have permissions to search or see this forum skip only this forum/category continue; } $selected = (in_array($row['forum_id'], $search_forum)) ? ' selected="selected"' : ''; if ($row['left_id'] > $cat_right) { // make sure we don't forget anything $s_forums .= $holding; $holding = ''; } if ($row['right_id'] - $row['left_id'] > 1) { $cat_right = max($cat_right, $row['right_id']); $holding .= '<option value="' . $row['forum_id'] . '"' . $selected . '>' . $padding . $row['forum_name'] . '</option>'; } else { $s_forums .= $holding . '<option value="' . $row['forum_id'] . '"' . $selected . '>' . $padding . $row['forum_name'] . '</option>'; $holding = ''; } } if ($holding) { $s_forums .= $holding; } unset($pad_store); unset($rowset); if (!$s_forums) { trigger_error('NO_SEARCH'); } // Number of chars returned $s_characters = '<option value="-1">' . $user->lang['ALL_AVAILABLE'] . '</option>'; $s_characters .= '<option value="0">0</option>'; $s_characters .= '<option value="25">25</option>'; $s_characters .= '<option value="50">50</option>'; for ($i = 100; $i <= 1000; $i += 100) { $selected = ($i == 300) ? ' selected="selected"' : ''; $s_characters .= '<option value="' . $i . '"' . $selected . '>' . $i . '</option>'; } $s_hidden_fields = array('t' => $topic_id); if ($_SID) { $s_hidden_fields['sid'] = $_SID; } if (!empty($_EXTRA_URL)) { foreach ($_EXTRA_URL as $url_param) { $url_param = explode('=', $url_param, 2); $s_hidden_fields[$url_param[0]] = $url_param[1]; } } $template->assign_vars(array( 'S_SEARCH_ACTION' => append_sid("{$phpbb_root_path}search.$phpEx", false, true, 0), // We force no ?sid= appending by using 0 'S_HIDDEN_FIELDS' => build_hidden_fields($s_hidden_fields), 'S_CHARACTER_OPTIONS' => $s_characters, 'S_FORUM_OPTIONS' => $s_forums, 'S_SELECT_SORT_DIR' => $s_sort_dir, 'S_SELECT_SORT_KEY' => $s_sort_key, 'S_SELECT_SORT_DAYS' => $s_limit_days, 'S_IN_SEARCH' => true, )); // only show recent searches to search administrators if ($auth->acl_get('a_search')) { // Handle large objects differently for Oracle and MSSQL switch ($db->get_sql_layer()) { case 'oracle': $sql = 'SELECT search_time, search_keywords FROM ' . SEARCH_RESULTS_TABLE . ' WHERE dbms_lob.getlength(search_keywords) > 0 ORDER BY search_time DESC'; break; case 'mssql_odbc': case 'mssqlnative': $sql = 'SELECT search_time, search_keywords FROM ' . SEARCH_RESULTS_TABLE . ' WHERE DATALENGTH(search_keywords) > 0 ORDER BY search_time DESC'; break; default: $sql = 'SELECT search_time, search_keywords FROM ' . SEARCH_RESULTS_TABLE . ' WHERE search_keywords <> \'\' ORDER BY search_time DESC'; break; } $result = $db->sql_query_limit($sql, 5); while ($row = $db->sql_fetchrow($result)) { $keywords = $row['search_keywords']; $template->assign_block_vars('recentsearch', array( 'KEYWORDS' => $keywords, 'TIME' => $user->format_date($row['search_time']), 'U_KEYWORDS' => append_sid("{$phpbb_root_path}search.$phpEx", 'keywords=' . urlencode(htmlspecialchars_decode($keywords))) )); } $db->sql_freeresult($result); } // Output the basic page page_header($user->lang['SEARCH']); $template->set_filenames(array( 'body' => 'search_body.html') ); make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx")); page_footer();