PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i5h-3LL

HOME


5h-3LL 1.0
DIR: /srv/http/vyvoj.adent.cz/egroupware/pfi/phpbrain/inc
/srv/http/vyvoj.adent.cz/egroupware/pfi/phpbrain/inc/
Upload File:
Current File : /srv/http/vyvoj.adent.cz/egroupware/pfi/phpbrain/inc/class.sokb.inc.php
<?php
/**************************************************************************\
* eGroupWare - KnowledgeBase                                               *
* http://www.egroupware.org                                                *
* Written by Alejandro Pedraza [alpeb AT users.sourceforge DOT net]        *
* ------------------------------------------------------------------------ *
*  Started off as a port of phpBrain - http://vrotvrot.com/phpBrain/	   *
*  but quickly became a full rewrite					                   *
* ------------------------------------------------------------------------ *
*  This program is free software; you can redistribute it and/or modify it *
*  under the terms of the GNU General Public License as published by the   *
*  Free Software Foundation; either version 2 of the License, or (at your  *
*  option) any later version.                                              *
\**************************************************************************/

	/* $Id: class.sokb.inc.php 24575 2007-10-20 16:43:08Z jgordor $ */

	/**
	* Data manipulation layer of the Knowledge Base. Methods to be used only  by methods in the bo class.
	*
	* Last Editor:	$Author: jgordor $
	* @author		Alejandro Pedraza
	* @package		phpbrain
	* @version		$Revision: 24575 $
	* @license		GPL
	**/
	class sokb
	{
		/**
		* Database object
		*
		* @access	private
		* @var		egw_db
		*/
		var $db;

		/**
		* Number of rows in result set
		*
		* @access	public
		* @var		int
		*/
		var $num_rows;

		/**
		* Number of unanswered questions in result set
		*
		* @access	public
		* @var		int
		*/
		var $num_questions;

		/**
		* Number of comments in result set
		*
		* @access	public
		* @var		int
		*/
		var $num_comments;

		/**
		* Type of LIKE SQL operator to use
		*
		* @access	private
		* @var		string
		*/
		var $like;

		/**
		* Class constructor
		*
		* @author	Alejandro Pedraza
		* @access	public
		**/
		function sokb()
		{
			$this->db	= clone($GLOBALS['phpgw']->db);
			$this->db->set_app('phpbrain');

            // postgresql is case sensite by default, so make it case insensitive
            if ($this->db->Type == 'pgsql')
            {
                $this->like = 'ILIKE';
            }
            else
            {
                $this->like = 'LIKE';
            }
		}

		/**
		* Returns array of articles
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	array	$owners			Users ids accessible by current user
		* @param	array	$categories		Categories ids
		* @param	int		$start			For pagination
		* @param	int		$upper_limit	For pagination
		* @param	srting	$sort			Sorting direction: ASC | DESC
		* @param	string	$order			Sorting field name
		* @param	mixed	$publish_filter	To filter pusblished or unpublished entries
		* @param	string	$query			Search string
		* @return	array					Articles
		*/
		function search_articles($owners, $categories, $start, $upper_limit = '', $sort, $order, $publish_filter = False, $query)
		{
			$where = array(
				'user_id' => $owners,
				'cat_id'  => !$categories ? 0 : $categories,
			);
			if ($publish_filter && $publish_filter != 'all') 
			{
				$where['published'] = (int) ($publish_filter == 'published');
			}
			$fields = '*';
			$fields .= ",(SELECT count(*) FROM phpgw_kb_files WHERE art_id=phpgw_kb_articles.art_id) AS files";

			if ($query)
			{
				$words = $likes = $scores = array();
				foreach (explode(' ',$query) as $word)
				{
					$scores[] = 'keyword='.$this->db->quote($word);

					if ((int)$word) 
					{
						$likes[] = 'phpgw_kb_articles.art_id='.(int)$word;
						continue;	// numbers are only searched as article-id
					}
					foreach(array('title','topic','text') as $col)
					{
						$likes[] = $col.' '.$this->like.' '.$this->db->quote('%'.$word.'%');
					} 
				}
				$score = 'SELECT sum(score) FROM phpgw_kb_search WHERE art_id=phpgw_kb_articles.art_id AND ('.implode(' OR ',$scores).')';
				$fields .= ",($score) AS pertinence";
				
				$where[] = "(($score) > 0 OR ".implode(' OR ',$likes).')';
			}
			$order_sql = array();
			if (preg_match('/^[a-z_0-9]+$/',$order))
			{
				$order_sql[] = $order.' '.($sort != 'DESC' ? 'ASC' : 'DESC');
			}
			if ($query)
			{
				$order_sql[] = "pertinence DESC";
			}
			if (!$order && !$query)
			{
				$order_sql[] = "modified DESC";
			}
			$order_sql = ' ORDER BY ' . implode(',', $order_sql);

			$this->db->select('phpgw_kb_articles','COUNT(*)',$where,__LINE__,__FILE__);
			$this->num_rows = $this->db->next_record() ? $this->db->f(0) : 0;
			
			$this->db->select('phpgw_kb_articles',$fields,$where,__LINE__,__FILE__,$start,$order_sql);
			$this->db->query($sql, __LINE__, __FILE__,$start,0);

			return $this->results_to_array($dummy);

/* not working old code: did return more then max_matches entries
			$order = $this->db->db_addslashes($order);
			if ($sort != 'DESC') $sort = 'ASC';

			// We use COALESCE (VALUE in case of maxdb) to turn NULLs into zeros, to avoid some databases (postgres and maxdb, don't know about mssql)
			// to sort records with score NULL before records with a score > 0.
			$score = (($this->db->Type == 'maxdb')? 'VALUE(SUM(phpgw_kb_search.score), 0)' : 'SUM(COALESCE(phpgw_kb_search.score))') . ' AS pertinence';
            // have to figure out later if maxdb is broken here...
			$files_field = (($this->db->Type == 'maxdb')? 'VALUE(art_file)' : 'COUNT(COALESCE(art_file))') . ' AS files';

			$fields = array('phpgw_kb_articles.art_id', 'title', 'topic', 'views', 'cat_id', 'published', 'user_id', 'created', 'modified', 'votes_1', 'votes_2', 'votes_3', 'votes_4', 'votes_5', $score, $files_field);
			$fields_str = implode(', ', $fields);
			$owners = implode(', ', $owners);

			$sql = "SELECT $fields_str FROM phpgw_kb_articles LEFT JOIN phpgw_kb_search ON phpgw_kb_articles.art_id=phpgw_kb_search.art_id ";
            $sql .= "LEFT JOIN phpgw_kb_files ON phpgw_kb_articles.art_id=phpgw_kb_files.art_id ";
            
 			$sql .= "WHERE user_id IN ($owners)";
			if ($publish_filter && $publish_filter!='all') 
			{
				($publish_filter == 'published')? $publish_filter = 1 : $publish_filter = 0;
				$sql .= " AND published=$publish_filter";
			}
			if (!$categories)
			{
				$sql .= " AND cat_id = 0";
			}
			else
			{
				$categories = implode(",", $categories);
				$sql .= " AND cat_id IN(" . $categories . ")";
			}

			if ($query)
			{
				$words_init = explode(' ', $query);
				$words = array();
				foreach ($words_init as $word_init)
				{
					$words[] = $this->db->db_addslashes($word_init);
				}
				$likes = array();
				foreach ($words as $word)
				{
					if ((int)$word) 
					{
						$likes[] = "phpgw_kb_articles.art_id='$word'";
						break;
					}
					$likes[] = "title {$this->like} '%$word%' OR topic {$this->like} '%$word%' OR text {$this->like} '%$word%'";
				}
				$likes = implode(' OR ', $likes);
			
				if ($likes)
				{
					// build query for results matching keywords (these are the most relevant results, and so appear first)
					$sql_keywords = $sql . " AND (keyword='" . implode("' OR keyword='", $words) . "')";

					// build query for the rest of results (looking in title, topic and text only). These appear after the previous ones are shown.
					// I must use the negation of the previous conditions to avoid shown repeated records
					$sql_rest = $sql . " AND (keyword!='" . implode("' AND keyword!='", $words) . "' AND $likes)";
				}
			}

			// Group by on all fields to return unique records and calculate pertinence scores
			$groupby = " GROUP BY phpgw_kb_articles.art_id, title, topic, views, cat_id, published, user_id, created, modified, votes_1, votes_2, votes_3, votes_4, votes_5";
			$order_sql = array();
			if ($order)
			{
				$order_sql[] = "$order $sort";
			}
			if ($query)
			{
				$order_sql[] = "pertinence DESC";
			}
			if (!$order && !$query)
			{
				$order_sql[] = "modified DESC";
			}
			$order_sql = ' ORDER BY ' . implode(',', $order_sql);	// only PHP lets me write crap like this

			if ($query)
			{
				$sqls[0] = $sql_keywords.$groupby.$order_sql;
				$sqls[1] = $sql_rest.$groupby.$order_sql;
			}
			else
			{
				$sqls[0] = $sql.$groupby.$order_sql;
			}

			//echo "sqls: "._debug_array($sqls);
			$articles = array();
			$this->num_rows = 0;
			foreach ($sqls as $sql)
			{
				$this->db->query($sql, __LINE__, __FILE__);
				$this->num_rows += $this->db->num_rows();
				$this->db->limit_query($sql, $start, __LINE__, __FILE__, $upper_limit);
				$start = $this->db->num_rows();
				$articles = array_merge($articles, $this->results_to_array($fields));
			}

			return $articles;
*/
		}

		/**
		* Returns results of advanced search
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	array	$owners			User ids accessible by current user
		* @param	array	$cats_ids		Categories filtering
		* @param	string	$ocurrences		Field name where to search
		* @param	string	$pub_date		Articles from last 3 or 6 months, or last year
		* @param	int		$start			For pagination
		* @param	int		$num_res		For pagination
		* @param	string	$all_words		'with all the words' filtering
		* @param	string	$phrase			'exact phrase' filtering
		* @param	string	$one_word		'with at least one of the words' filtering
		* @param	string	$without_words	'without the words' filtering
		* @param	int		$cat			Don't know
		* @param	bool	$include_subs	Include subcategories when filtering by categories. Seems to not being working
		* @return	array					Articles
		* @todo		use params $cat and $include_subs
		*/
		function adv_search_articles($owners, $cats_ids, $ocurrences, $pub_date, $start, $num_res, $all_words, $phrase, $one_word, $without_words, $cat, $include_subs)
		{
			$fields= array('phpgw_kb_articles.art_id', 'title', 'topic', 'views', 'cat_id', 'published', 'user_id', 'created', 'modified', 'votes_1', 'votes_2',  'votes_3', 'votes_4', 'votes_5');
			$fields_str	= implode(' , ', $fields);

			// permissions filtering
			$owners	= implode(', ', $owners);
			$sql = "SELECT DISTINCT $fields_str FROM phpgw_kb_articles LEFT JOIN phpgw_kb_search ON phpgw_kb_articles.art_id=phpgw_kb_search.art_id WHERE user_id IN ($owners)";

			// categories filtering
			$cats_ids	= implode (',', $cats_ids);
			if ($cats_ids) $sql .= " AND cat_id IN ($cats_ids)";

			// date filtering
			switch ($pub_date)
			{
				case '3':
					$sql .= " AND created>" . mktime(0, 0, 0, date('n')-3);
					break;
				case '6':
					$sql .= " AND created>" . mktime(0, 0, 0, date('n')-6);
					break;
				case 'year':
					$sql .= " AND created>" . mktime(0, 0, 0, date('n')-12);
					break;
			}

			// ocurrences filtering
			switch ($ocurrences)
			{
				case 'title':
					$target_fields = array('title');
					break;
				case 'topic':
					$target_fields = array('topic');
					break;
				case 'text':
					$target_fields = array('text');
					break;
				default:
					$target_fields = array('title', 'topic', 'keyword', 'text');
					break;
			}

			// "with all the words" filtering
			$all_words = $this->db->db_addslashes($all_words);
			$all_words = strlen($all_words)? explode(' ', $all_words) : False;
			$each_field = array();
			if ($all_words)
			{
				foreach ($all_words as $word)
				{
					$each_field[] = "(" . implode(" {$this->like} '%$word%' OR ", $target_fields) . " {$this->like} '%$word%')";
				}
				if ($each_field)
				{
					$sql .= " AND " . implode(" AND ", $each_field);
				}
			}

			// "with the exact phrase" filtering
			$phrase = $this->db->db_addslashes($phrase);
			if ($phrase)
			{
				$sql .= " AND (" . implode (" {$this->like} '%$phrase%' OR ", $target_fields) . " {$this->like} '%$phrase%')";
			}

			// "With at least one of the words" filtering
			$one_word = $this->db->db_addslashes($one_word);
			$one_word = strlen($one_word)? explode(' ', $one_word) : False;
			if ($one_word)
			{
				$each_field = array();
				foreach ($one_word as $word)
				{
					$each_field[] = "(" . implode(" {$this->like} '%$word' OR ", $target_fields) . " {$this->like} '%$word%')";
				}
				$sql .= " AND (". implode (" OR ", $each_field) . ")";
			}

			// "Without the words" filtering
			$without_words = $this->db->db_addslashes($without_words);
			$without_words = strlen($without_words)? explode(' ', $without_words) : False;
			$each_field = array();
			if ($without_words)
			{
				foreach ($without_words as $word)
				{
					$each_field[] = "(" . implode(" NOT {$this->like} '%word' AND ", $target_fields) . " NOT {$this->like} '%$word%')";
				}
				$sql .= " AND " . implode(" AND ", $each_field);
			}

			// do the query
			//echo "query: $sql <br>";
			$this->db->query($sql, __LINE__, __FILE__);
			$this->num_rows = $this->db->num_rows();
			$this->db->limit_query($sql, $start, __LINE__, __FILE__, $num_res);
			return $this->results_to_array($fields);
		}

		/**
		* Fetches results from database and returns array of articles
		*
		* @author	Alejandro Pedraza
		* @access 	private
		* @param	array	$fields	Which fields to fetch
		* @return	array	Articles
		*/
		function results_to_array($fields)
		{
			$articles = array();
			while(($article = $this->db->row(true)))
			{
				$article['username'] = $GLOBALS['egw']->common->grab_owner_name($article['user_id']);
				$article['total_votes'] = $article['votes_1'] + $article['votes_2'] + $article['votes_3'] + $article['votes_4'] + $article['votes_5'];
				if ($article['total_votes'])
				{
					$article['average_votes'] = (1*$article['votes_1'] + 2*$article['votes_2'] + 3*$article['votes_3'] + 4*$article['votes_4'] + 5*$article['votes_5']) / ($article['total_votes']);
				}
				else
				{
					$article['average_votes'] = 0;	// avoid division by zero
				}
				$articles[] = $article;
			}
			return $articles;

/* old code requires the $fields to be named
			for ($i=0; $this->db->next_record(); $i++)
			{
				foreach ($fields as $field)
				{
                    if (preg_match('/.* AS (.*)/', $field, $matches)) {
                        $modified_field = $matches[1];
                    } else {
                        $modified_field = $field;
                    }
					$articles[$i][$modified_field] = $this->db->f($modified_field);
				}
				$articles[$i]['art_id'] = $this->db->f('art_id');
				$username = $GLOBALS['phpgw']->accounts->get_account_name($articles[$i]['user_id'], $lid, $fname, $lname);
				$articles[$i]['username'] = $fname . ' ' . $lname;
				//$articles[$i]['files'] = unserialize($articles[$i]['files']);
				$articles[$i]['total_votes'] = $articles[$i]['votes_1'] + $articles[$i]['votes_2'] + $articles[$i]['votes_3'] + $articles[$i]['votes_4'] + $articles[$i]['votes_5'];
				if ($articles[$i]['total_votes'])
				{
					$articles[$i]['average_votes'] = (1*$articles[$i]['votes_1'] + 2*$articles[$i]['votes_2'] + 3*$articles[$i]['votes_3'] + 4*$articles[$i]['votes_4'] + 5*$articles[$i]['votes_5']) / ($articles[$i]['total_votes']);
				}
				else
				{
					$articles[$i]['average_votes'] = 0;	// avoid division by zero
				}
			}
*/
		}

		/**
		* Upgrades the keywords in the phpgw_kb_search table
		*
		* @author	Ralf Becker
		* @access	public
		* @param	int		$art_id	Article ID
		* @param	string	$words			all Keyword(s)
		* @param	mixed	$upgrade_key	Whether to give more or less score to $word
		* @return	void
		*/
		function update_keywords($art_id, $words, $upgrade_key)
		{
			$words = array_diff(explode(' ',$words),array(''));

			// delete all existing and NOT longer mentioned keywords
			$this->db->delete('phpgw_kb_search',!$words ? array('art_id' => $art_id) :
				$this->db->expression('phpgw_kb_search',array('art_id' => $art_id),' AND NOT ',array('keyword'=>$words)),
				__LINE__,__FILE__);
				
			foreach($words as $word)
			{
				$this->update_keyword($art_id,$word,$upgrade_key);
			}
		}

		/**
		* Upgrades phpgw_kb_search table given user input
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int		$art_id	Article ID
		* @param	string	$word			Keyword
		* @param	mixed	$upgrade_key	Whether to give more or less score to $word
		* @return	void
		*/
		function update_keyword($art_id, $word, $upgrade_key)
		{
			$word = $this->db->db_addslashes(substr($word, 0, 30));

			// retrieve current score
			$sql = "SELECT score FROM phpgw_kb_search WHERE keyword='$word' AND art_id=$art_id";
			$this->db->query($sql, __LINE__, __FILE__);
			$keyword_exists = $this->db->next_record();
			if ($keyword_exists && $upgrade_key != 'same')
			{
				// upgrade score
				$old_score = $this->db->f('score');
				$new_score = $upgrade_key ? $old_score + 1 : $old_score - 1;
				$sql = "UPDATE phpgw_kb_search SET score=$new_score WHERE keyword='$word' AND art_id=$art_id";
				$this->db->query($sql, __LINE__, __FILE__);
			}
			elseif (!$keyword_exists || $upgrade_key != 'same')
			{
				// create new entry for word
				$sql = "INSERT INTO phpgw_kb_search (keyword, art_id, score) VALUES('$word', $art_id, 1)";
				$this->db->query($sql, __LINE__, __FILE__);
			}
		}

		/**
		* Returns unanswered questions
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	array	$owners			User ids accessible by current user
		* @param	array	$categories		Categories ids
		* @param	int		$start			For pagination
		* @param	int		$upper_limit	For pagination
		* @param	srting	$sort			Sorting direction: ASC | DESC
		* @param	string	$order			Sorting field name
		* @param	mixed	$publish_filter	To filter pusblished or unpublished entries
		* @param	string	$query			Search string
		* @return	array					Questions
		*/
		function unanswered_questions($owners, $categories, $start, $upper_limit='', $sort, $order, $publish_filter=False, $query)
		{
			$fields = array('question_id', 'user_id', 'summary', 'details', 'cat_id', 'creation', 'published');
			$fields_str = implode(', ', $fields);
			$owners = implode(', ', $owners);
			$sql = "SELECT $fields_str FROM phpgw_kb_questions WHERE user_id IN ($owners)";
			if ($publish_filter && $publish_filter!='all') 
			{
				($publish_filter == 'published')? $publish_filter = 1 : $publish_filter = 0;
				$sql .= " AND published=$publish_filter";
			}
			if (!$categories)
			{
				$sql .= " AND cat_id = 0";
			}
			else
			{
				$categories = implode(",", $categories);
				$sql .= " AND cat_id IN(" . $categories . ")";
			}
			if ($query)
			{
				$query = $this->db->db_addslashes($query);
				$words = explode(' ', $query);
				$sql .= " AND (summary {$this->like} '%" . implode("%' OR summary {$this->like} '%", $words) . "%' OR details {$this->like} '%" . implode("%' OR details {$this->like} '%", $words) . "%')";
			}
			if ($order)
			{
				$sql .= " ORDER BY $order $sort";
			}
			//echo "sql: $sql <br><br>";
			$this->db->query($sql, __LINE__, __FILE__);
			$this->num_rows = $this->db->num_rows();
			$this->num_questions = $this->num_rows;
			$this->db->limit_query($sql, $start, __LINE__, __FILE__, $upper_limit);
			$questions = array();
			for ($i=0; $this->db->next_record(); $i++)
			{
				foreach ($fields as $field)
				{
					$questions[$i][$field] = $this->db->f($field);
				}
				$username = $GLOBALS['phpgw']->accounts->get_account_name($questions[$i]['user_id'], $lid, $fname, $lname);
				$questions[$i]['username'] = $fname . ' ' . $lname;
			}
			return $questions;
		}

		/**
		* Saves a new or edited article
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	array	$contents	article contents
		* @param	bool	$is_new		True if it's a new article, False if its an edition
		* @param	bool	$publish	True if the article is to be published without revision
		* @return	mixed				article id or False if failure
		**/
		function save_article($contents, $is_new, $publish = False)
		{
			$current_time = time();
			if ($is_new)
			{
				($publish)? $publish = 1 : $publish = 0;
				$q_id = $contents['answering_question']? $contents['answering_question'] : 0;
				$sql = "INSERT INTO phpgw_kb_articles (q_id, title, topic, text, cat_id, published, user_id, created, modified, modified_user_id, votes_1, votes_2, votes_3, votes_4, votes_5) VALUES ("
						. "$q_id, '"
						. $this->db->db_addslashes($contents['title']) . "', '"
						. $this->db->db_addslashes($contents['topic']) . "', '"
						. $this->db->db_addslashes($contents['text']) . "', "
						. (int) $contents['cat_id'] . ", "
						. $publish . ", "
						. $GLOBALS['phpgw_info']['user']['account_id'] . ", "
						. $current_time . ", " . $current_time . ", "
						. $GLOBALS['phpgw_info']['user']['account_id'] . ", "
						. " 0, 0, 0, 0, 0)";
				$this->db->query($sql, __LINE__, __FILE__);
				$article_id = $this->db->get_last_insert_id('phpgw_kb_articles', 'art_id');

				// update table phpgw_kb_search with keywords. Even if no keywords were introduced, generate an entry
				$this->update_keywords($article_id, $contents['keywords'], 'same');

				// if publication is automatic and the article answers a question, delete the question
				if ($publish && $contents['answering_question'])
				{
					$sql = "DELETE FROM phpgw_kb_questions WHERE question_id=$q_id";
					$this->db->query($sql, __LINE__, __FILE__);
				}

				return $article_id;
			}
			else
			{
				$sql = "UPDATE phpgw_kb_articles SET "
						." title='" . $this->db->db_addslashes($contents['title'])
						."', topic='" . $this->db->db_addslashes($contents['topic'])
						."', text='" . $this->db->db_addslashes($contents['text'])
						."', cat_id='" . (int)($contents['cat_id'])
						."', modified=" . $current_time
						.", modified_user_id=" . $GLOBALS['phpgw_info']['user']['account_id']
						." WHERE art_id=" . $contents['editing_article_id'];
				$this->db->query($sql, __LINE__, __FILE__);
				$queries_ok = false;
				if ($this->db->affected_rows()) $queries_ok = true;

				// update keywords
				$this->update_keywords($contents['editing_article_id'],$contents['keywords'], True, False);

				if ($queries_ok)
				{
					return $contents['editing_article_id'];
				}
				else
				{
					return False;
				}
			}
		}

		/**
		* Changes article owner when user is deleted
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int	$owner		actual owner
		* @param	int	$new_owner	new owner
		* @return	void
		**/
		function change_articles_owner($owner, $new_owner)
		{
			$sql = "UPDATE phpgw_kb_articles SET user_id='$new_owner' WHERE user_id='$owner'";
			$this->db->query($sql, __LINE__, __FILE__);
		}

		/**
		* Deletes article
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int		$art_id		article id
		* @return	bool	1 on success, 0 on failure
		**/
		function delete_article($art_id)
		{
			$sql = "DELETE FROM phpgw_kb_articles WHERE art_id=$art_id";
			if (!$this->db->query($sql, __LINE__, __FILE__)) return 0;
			return 1;
		}

		/**
		* Deletes question
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int		$q_id		Question id
		* @return	bool	1 on success, 0 on failure
		**/
		function delete_question($q_id)
		{
			$sql = "DELETE FROM phpgw_kb_questions WHERE question_id=$q_id";
			if (!$this->db->query($sql, __LINE__, __FILE__)) return 0;
			return 1;
		}

		/**
		* Returns latest articles entered
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int	$parent_cat	Category id
		* @return	array	Articles
		*/
		function get_latest_articles($parent_cat)
		{
			$sql = "SELECT art_id, title, topic, text, modified, votes_1, votes_2, votes_3, votes_4, votes_5 FROM phpgw_kb_articles";
			$this->db->query($sql, __LINE__, __FILE__);

			$articles = array();
			while ($this->db->next_record())
			{
				$rating = 1*$this->db->f('votes_1') + 2*$this->db->f('votes_2') + 3*$this->db->f('votes_3') + 4*$this->db->f('votes_4') + 5*$this->db->f('votes_5');
				$articles[$this->db->f('art_id')] = array(
					'title'		=> $this->db->f('title'),
					'topic'		=> $this->db->f('topic'),
					'text'		=> $this->db->f('text'),
					'modified'	=> $this->db->f('modified'),
					'rating'	=> $rating
				);
			}

			return $articles;
		}

		/**
		* Returns article
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int		$art_id		article id
		* @return	array	Article
		**/
		function get_article($art_id)
		{
			$fields = array('art_id', 'title', 'topic', 'text', 'views', 'cat_id', 'published', 'user_id', 'created', 'modified', 'modified_user_id', 'votes_1', 'votes_2', 'votes_3', 'votes_4', 'votes_5');
			$fields_str = implode(", ", $fields);

			$sql =	"SELECT $fields_str FROM phpgw_kb_articles WHERE art_id=$art_id";
			//echo "sql: $sql <br>";
			$this->db->query($sql, __LINE__, __FILE__);
			$article = array();
			if (!$this->db->next_record()) return 0;
			foreach ($fields as $field)
			{
				$article[$field] = $this->db->f($field);
			}

			// get article's attached files names
			$this->db->query("SELECT art_file, art_file_comments FROM phpgw_kb_files WHERE art_id=$art_id", __LINE__, __FILE__);
			$article['files'] = array();
			$i = 0;
			while ($this->db->next_record())
			{
				$article['files'][$i]['file'] = $this->db->f('art_file');
				$article['files'][$i]['comment'] = $this->db->f('art_file_comments');
				$i++;
			}

			// get article's attached urls
			$this->db->query("SELECT art_url, art_url_title FROM phpgw_kb_urls WHERE art_id=$art_id", __LINE__, __FILE__);
			$article['urls'] = array();
			$i = 0;
			while ($this->db->next_record())
			{
				$article['urls'][$i]['link'] = $this->db->f('art_url');
				$article['urls'][$i]['title'] = $this->db->f('art_url_title');
				$i++;
			}

			// get article's keywords
			$this->db->query("SELECT keyword FROM phpgw_kb_search WHERE art_id=$art_id", __LINE__, __FILE__);
			$article['keywords'] = array();
			while ($this->db->next_record())
			{
				$article['keywords'][] = $this->db->f('keyword');
			}
			$article['keywords'] = implode(' ', $article['keywords']);

			// normalize vote frequence to the range 0 - 40
			$votes = array();
			$article['total_votes'] = $article['votes_1'] + $article['votes_2'] + $article['votes_3'] + $article['votes_4'] + $article['votes_5'];
			if ($article['total_votes'])
			{
				$article['average_votes'] = ($article['votes_1'] + 2*$article['votes_2'] + 3*$article['votes_3'] + 4*$article['votes_4'] + 5*$article['votes_5']) / $article['total_votes'];
			}
			else
			{
				$article['average_votes'] = 0;
			}

			return $article;
		}

		/**
		* Returns all articles ids from a given owner
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int		$owner		owner id
		* @return	array	Articles ids
		**/
		function get_articles_ids($owner)
		{
			$sql = "SELECT art_id FROM phpgw_kb_articles WHERE user_id=$owner";
			$this->db->query($sql, __LINE__, __FILE__);
			$articles_ids = array();
			while ($this->db->next_record())
			{
				$articles_ids[] = $this->db->f('art_id');
			}
			return $articles_ids;
		}

		/**
		* Increments the view count of a published article
		*
		* @author	Alejandro Pedraza
		* @param	int	$art_id			article id
		* @param	int	$current_count	current view count
		* @return	void
		**/
		function register_view($art_id, $current_count)
		{
			$current_count ++;
			$sql = "UPDATE phpgw_kb_articles SET views=$current_count WHERE art_id=$art_id";
			$this->db->query($sql, __LINE__, __FILE__);
		}

		/**
		* Returns article's comments
		*
		* @author	Alejandro Pedraza
		* @param	int		$art_id		article id
		* @param	int		$limit		Number of comments to return
		* @return	array				Comments
		*/
		function get_comments($art_id, $limit)
		{
			$fields = array('comment_id', 'user_id', 'comment', 'entered', 'art_id', 'published');
			$fields_str = implode(", ", $fields);
			$sql = "SELECT " . $fields_str . " FROM phpgw_kb_comment WHERE art_id=$art_id ORDER BY entered DESC";
			$this->db->query($sql, __LINE__, __FILE__);
			$this->num_comments = $this->db->num_rows();
			if ($limit)
			{
				$this->db->limit_query($sql, 0, __LINE__, __FILE__, $limit);
			}
			$comments = array();
			for ($i=0; $this->db->next_record(); $i++)
			{
				foreach ($fields as $field)
				{
					$comments[$i][$field] = $this->db->f($field);
				}
				$GLOBALS['phpgw']->accounts->get_account_name($comments[$i]['user_id'], $lid, $fname, $lname);
				$comments[$i]['username'] = $fname . ' ' . $lname;
			}
			return $comments;
		}

		/**
		* Delete article's comments
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int		$art_id		article id
		* @return	void
		*/
		function delete_comments($art_id)
		{
			$sql = "DELETE FROM phpgw_kb_comment WHERE art_id=$art_id";
			$this->db->query($sql, __LINE__, __FILE__);
		}

		/**
		* Delete article's ratings
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int		$art_id		article id
		* @return	void
		*/
		function delete_ratings($art_id)
		{
			$sql = "DELETE FROM phpgw_kb_ratings WHERE art_id=$art_id";
			$this->db->query($sql, __LINE__, __FILE__);
		}

		/**
		* Delete article's file entries in phpgw_kb_files
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int		$art_id		article id
		* @param	string	$file_to_erase	File name
		* @return	bool					1 on success, 0 on failure
		*/
		function delete_files($art_id, $file_to_erase = false)
		{
			$files = '';
			if ($file_to_erase)
			{
				$file_to_erase = $this->db->db_addslashes($file_to_erase);
				$files = " AND art_file='$file_to_erase'";
			}
			$sql = "DELETE FROM phpgw_kb_files WHERE art_id=$art_id$files";
			$this->db->query($sql, __LINE__, __FILE__);
			if ($this->db->affected_rows()) return True;
			return False;
		}

		/**
		* Delete article's urls
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int		$art_id		article id
		* @return	void
		*/
		function delete_urls($art_id)
		{
			$sql = "DELETE FROM phpgw_kb_urls WHERE art_id=$art_id";
			$this->db->query($sql, __LINE__, __FILE__);
		}

		/**
		* Returns an article related comments
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int		$art_id	Article id
		* @param	array	$owners	Accessible owners to current user
		* @return	array	IDs and titles of articles
		*/
		function get_related_articles($art_id, $owners)
		{
			$owners = implode(', ', $owners);
			$sql = "SELECT phpgw_kb_articles.art_id, phpgw_kb_articles.title FROM phpgw_kb_related_art, phpgw_kb_articles WHERE phpgw_kb_related_art.related_art_id=phpgw_kb_articles.art_id AND phpgw_kb_related_art.art_id=$art_id AND phpgw_kb_articles.user_id IN ($owners)";
			$this->db->query($sql, __LINE__, __FILE__);
			$related = array();
			while ($this->db->next_record())
			{
				$related[] = array('art_id' => $this->db->f('art_id'), 'title' => $this->db->f('title'));
			}
			return $related;
		}

		/**
		* Tells if the current user has already rated the article
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int		$art_id		article id
		* @return	bool				1 if he has, 0 if not
		**/
		function user_has_voted($art_id)
		{
			$sql = "SELECT * FROM phpgw_kb_ratings WHERE user_id=" . $GLOBALS['phpgw_info']['user']['account_id'] . " AND art_id=$art_id";
			$this->db->query($sql, __LINE__, __FILE__);
			if ($this->db->next_record()) return 1;
			return 0;
		}

		/**
		* Stores new comment
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	string	$comment	comment text
		* @param	int		$art_id		article id
		* @param	bool	$publish	True if comment is to be published, False if not
		* @return	bool				1 on success, 0 on failure
		**/
		function add_comment($comment, $art_id, $publish)
		{
			$comment = $this->db->db_addslashes($comment);
			($publish)? $publish = 1 : $publish = 0;
			$sql = "INSERT INTO phpgw_kb_comment (user_id, comment, entered, art_id, published) VALUES("
					. $GLOBALS['phpgw_info']['user']['account_id'] . ", '$comment', " . time() . ", $art_id, $publish)";
			$this->db->query($sql, __LINE__, __FILE__);
			if (!$this->db->affected_rows()) return 0;
			return 1;
		}

		/**
		* Adds link to article
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	string	$url		Url
		* @param	string	$title		Url title
		* @param	int		$art_id		article id
		* @return	bool				1 on success, 0 on failure
		*/
		function add_link($url, $title, $art_id)
		{
			$sql = "INSERT INTO phpgw_kb_urls (art_id, art_url, art_url_title) VALUES ($art_id, '$url', '$title')";
			$this->db->query($sql, __LINE__, __FILE__);
			if (!$this->db->affected_rows()) return 0;
			return 1;
		}

		/**
		* Publishes article, and resets creation and modification date
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int		$art_id		article id
		* @return	int					Numbers of lines affected (should be 1, if not there's an error)
		**/
		function publish_article($art_id)
		{
			$sql = "UPDATE phpgw_kb_articles SET published=1, created=". time() . ", modified=" . time() . " WHERE art_id=$art_id";
			$this->db->query($sql, __LINE__, __FILE__);

			// check if the article answers a question, and if so, delete it
			$sql = "SELECT q_id FROM phpgw_kb_articles WHERE art_id=$art_id";
			$this->db->query($sql, __LINE__, __FILE__);
			if ($this->db->next_record())
			{
				$sql = "DELETE FROM phpgw_kb_questions WHERE question_id=".$this->db->f('q_id');
				$this->db->query($sql, __LINE__, __FILE__);
			}

			return True;
		}

		/**
		* Publishes question
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int		$q_id		Question id
		* @return	int					Numbers of lines affected (should be 1, if not there's an error)
		**/
		function publish_question($q_id)
		{
			$sql = "UPDATE phpgw_kb_questions SET published=1 WHERE question_id=$q_id";
			$this->db->query($sql, __LINE__, __FILE__);
			return ($this->db->affected_rows());
		}

		/**
		* Publishes article comment
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int	$art_id		Article ID
		* @param	int $comment_id	Comment ID
		* @return	int				Numbers of lines affected (should be 1, if not there's an error)
		*/
		function publish_comment($art_id, $comment_id)
		{
			$sql = "UPDATE phpgw_kb_comment SET published=1 WHERE art_id=$art_id AND comment_id=$comment_id";
			$this->db->query($sql, __LINE__, __FILE__);
			return ($this->db->affected_rows());
		}

		/**
		* Deletes article comment
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int	$art_id		Article ID
		* @param	int $comment_id	Comment ID
		* @return	int				Numbers of lines affected (should be 1, if not there's an error)
		*/
		function delete_comment($art_id, $comment_id)
		{
			$sql = "DELETE FROM phpgw_kb_comment WHERE art_id=$art_id AND comment_id=$comment_id";
			$this->db->query($sql, __LINE__, __FILE__);
			return ($this->db->affected_rows());
		}

		/**
		* Deletes article comment
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int	$art_id			Article ID
		* @param	int $delete_link	Link ID
		* @return	bool				1 on success, 0 on failure
		*/
		function delete_link($art_id, $delete_link)
		{
			$delete_link = $this->db->db_addslashes($delete_link);
			$sql = "DELETE FROM phpgw_kb_urls WHERE art_id=$art_id AND art_url='$delete_link'";
			$this->db->query($sql, __LINE__, __FILE__);
			if (!$this->db->affected_rows()) return 0;
			return 1;
		}

		/**
		* Increments vote_x in table
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int	$art_id			Article id
		* @param 	int	$rating			Rating between 1 and 5
		* @param	int	$current_rating	Number of current votes in that rating
		* @return	bool				1 on success, 0 on failure
		**/
		function add_vote($art_id, $rating, $current_rating)
		{
			$new_rating = $current_rating + 1;
			$sql = "UPDATE phpgw_kb_articles SET votes_" . $rating . "=$new_rating WHERE art_id=$art_id";
			$this->db->query($sql, __LINE__, __FILE__);
			if (!$this->db->affected_rows()) return 0;
			return 1;
		}

		/**
		* Registers that actual user has voted this article
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int	$art_id		article id
		* @return	bool			1 on success, 0 on failure
		**/
		function add_rating_user($art_id)
		{
			$sql = "INSERT INTO phpgw_kb_ratings (user_id, art_id) VALUES(" . $GLOBALS['phpgw_info']['user']['account_id'] . ", $art_id)";
			$this->db->query($sql, __LINE__, __FILE__);
			if (!$this->db->affected_rows()) return 0;
			return 1;
		}

		/**
		* Register file upload in the article's database record
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int		$article_id	Article id
		* @param	string	$file_name	File name
		* @return	bool			1 on success, 0 on failure
		*/
		function add_file($article_id, $file_name)
		{
			$file_name = $this->db->db_addslashes($file_name);
			$comment = $_POST['file_comment']? $_POST['file_comment'] : '';
			$comment = $this->db->db_addslashes($comment);

			$sql = "INSERT INTO phpgw_kb_files (art_id, art_file, art_file_comments) VALUES($article_id, '$file_name', '$comment')";
			$this->db->query($sql, __LINE__, __FILE__);
			if (!$this->db->next_record()) return 0;
			return 1;
		}

		/**
		* Checks if there is already an article in the db with the given ID
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int		$art_id		article id
		* @return	bool				1 if there is one, 0 if not
		**/
		function exist_articleID($article_id)
		{
			$sql = "SELECT art_id FROM phpgw_kb_articles WHERE art_id=" . $article_id;
			$this->db->query($sql, __LINE__, __FILE__);
			return $this->db->next_record();
		}

		/**
		* Returns ids of owners of articles
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	array	$articles	Ids of articles
		* @return	array				Article ids and owners ids
		*/
		function owners_list($articles)
		{
			$articles = implode(', ', $articles);
			$sql = "SELECT art_id, user_id FROM phpgw_kb_articles WHERE art_id IN($articles)";
			$this->db->query($sql, __LINE__, __FILE__);
			$owners = array();
			while ($this->db->next_record())
			{
				$owners[] = array('art_id' => $this->db->f('art_id'), 'user_id' => $this->db->f('user_id'));
			}
			return $owners;
		}

		/**
		* Adds related article to article
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int		$art_id		Article id
		* @param	array	$articles	Articles id to relate to $art_id
		* @return	bool				1 on success, 0 on failure
		*/
		function add_related($art_id, $articles)
		{
			$added = False;
			foreach ($articles as $article)
			{
				$sql = "INSERT INTO phpgw_kb_related_art (art_id, related_art_id) VALUES($art_id, $article)";
				$this->db->query($sql, __LINE__, __FILE__);
				if ($this->db->affected_rows()) $added = True;
			}
			return $added;
		}

		/**
		* Deletes related article to article
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int		$art_id		Article id
		* @param	int		$related_id	Article id to delete
		* @return	void
		*/
		function delete_related($art_id, $related_id, $all = False)
		{
			$sql_operator = $all? 'OR' : 'AND';
			$sql = "DELETE FROM phpgw_kb_related_art WHERE art_id=$art_id $sql_operator related_art_id=$related_id";
			$this->db->query($sql, __LINE__, __FILE__);
		}

		/**
		* Deletes entry in keywords table
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int		$art_id		Article id
		* @return	void
		*/
		function delete_search($art_id)
		{
			$sql = "DELETE FROM phpgw_kb_search WHERE art_id=$art_id";
			$this->db->query($sql, __LINE__, __FILE__);
		}

		/**
		* Adds question to database
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	array	$data		Question data
		* @param	bool	$publish	Whether to publish the question or not
		* @return	int				Numbers of lines affected (should be 1, if not there's an error)
		*/
		function add_question($data, $publish)
		{
			($publish)? $publish = 1 : $publish = 0;
			$sql = "INSERT INTO phpgw_kb_questions (user_id, summary, details, cat_id, creation, published) VALUES ("
					. $GLOBALS['phpgw_info']['user']['account_id'] . ", '"
					. $this->db->db_addslashes($data['summary']) . "', '"
					. $this->db->db_addslashes($data['details']) . "', "
					. (int)$data['cat_id'] . ", "
					. time() . ", "
					. $publish . ")";
			$this->db->query($sql, __LINE__, __FILE__);
			return $this->db->affected_rows();
		}

		/**
		* Returns question
		*
		* @author	Alejandro Pedraza
		* @access	public
		* @param	int		$q_id	Question id
		* @return	array			Question
		*/
		function get_question($q_id)
		{
			$fields = array('user_id', 'summary', 'details', 'cat_id', 'creation');
			$fields_str = implode(", ", $fields);

			$sql = "SELECT $fields_str FROM phpgw_kb_questions WHERE question_id=$q_id AND published=1";
			$this->db->query($sql, __LINE__, __FILE__);
			$question = array();
			while ($this->db->next_record())
			{
				foreach ($fields as $field)
				{
					$question[$field] = $this->db->f($field);
				}
			}
			return $question;
		}
	}
?>